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> 29d510296dSAlexei Starovoitov #include <bpf/skel_internal.h> 3071bb428fSJakub Kicinski 31b6c1cedbSJiong Wang #include "cfg.h" 3271bb428fSJakub Kicinski #include "main.h" 3373bb5b4fSJiong Wang #include "xlated_dumper.h" 3471bb428fSJakub Kicinski 35aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX "bpf_metadata_" 36aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1) 37aff52e68SYiFei Zhu 389023497dSTobias Klauser const char * const prog_type_name[] = { 399023497dSTobias Klauser [BPF_PROG_TYPE_UNSPEC] = "unspec", 409023497dSTobias Klauser [BPF_PROG_TYPE_SOCKET_FILTER] = "socket_filter", 419023497dSTobias Klauser [BPF_PROG_TYPE_KPROBE] = "kprobe", 429023497dSTobias Klauser [BPF_PROG_TYPE_SCHED_CLS] = "sched_cls", 439023497dSTobias Klauser [BPF_PROG_TYPE_SCHED_ACT] = "sched_act", 449023497dSTobias Klauser [BPF_PROG_TYPE_TRACEPOINT] = "tracepoint", 459023497dSTobias Klauser [BPF_PROG_TYPE_XDP] = "xdp", 469023497dSTobias Klauser [BPF_PROG_TYPE_PERF_EVENT] = "perf_event", 479023497dSTobias Klauser [BPF_PROG_TYPE_CGROUP_SKB] = "cgroup_skb", 489023497dSTobias Klauser [BPF_PROG_TYPE_CGROUP_SOCK] = "cgroup_sock", 499023497dSTobias Klauser [BPF_PROG_TYPE_LWT_IN] = "lwt_in", 509023497dSTobias Klauser [BPF_PROG_TYPE_LWT_OUT] = "lwt_out", 519023497dSTobias Klauser [BPF_PROG_TYPE_LWT_XMIT] = "lwt_xmit", 529023497dSTobias Klauser [BPF_PROG_TYPE_SOCK_OPS] = "sock_ops", 539023497dSTobias Klauser [BPF_PROG_TYPE_SK_SKB] = "sk_skb", 549023497dSTobias Klauser [BPF_PROG_TYPE_CGROUP_DEVICE] = "cgroup_device", 559023497dSTobias Klauser [BPF_PROG_TYPE_SK_MSG] = "sk_msg", 569023497dSTobias Klauser [BPF_PROG_TYPE_RAW_TRACEPOINT] = "raw_tracepoint", 579023497dSTobias Klauser [BPF_PROG_TYPE_CGROUP_SOCK_ADDR] = "cgroup_sock_addr", 589023497dSTobias Klauser [BPF_PROG_TYPE_LWT_SEG6LOCAL] = "lwt_seg6local", 599023497dSTobias Klauser [BPF_PROG_TYPE_LIRC_MODE2] = "lirc_mode2", 609023497dSTobias Klauser [BPF_PROG_TYPE_SK_REUSEPORT] = "sk_reuseport", 619023497dSTobias Klauser [BPF_PROG_TYPE_FLOW_DISSECTOR] = "flow_dissector", 629023497dSTobias Klauser [BPF_PROG_TYPE_CGROUP_SYSCTL] = "cgroup_sysctl", 639023497dSTobias Klauser [BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE] = "raw_tracepoint_writable", 649023497dSTobias Klauser [BPF_PROG_TYPE_CGROUP_SOCKOPT] = "cgroup_sockopt", 659023497dSTobias Klauser [BPF_PROG_TYPE_TRACING] = "tracing", 669023497dSTobias Klauser [BPF_PROG_TYPE_STRUCT_OPS] = "struct_ops", 679023497dSTobias Klauser [BPF_PROG_TYPE_EXT] = "ext", 689a97c9d2SQuentin Monnet [BPF_PROG_TYPE_LSM] = "lsm", 6993a3545dSJakub Sitnicki [BPF_PROG_TYPE_SK_LOOKUP] = "sk_lookup", 709023497dSTobias Klauser }; 719023497dSTobias Klauser 729023497dSTobias Klauser const size_t prog_type_name_size = ARRAY_SIZE(prog_type_name); 739023497dSTobias Klauser 74ec202509SPaul Chaignon enum dump_mode { 75ec202509SPaul Chaignon DUMP_JITED, 76ec202509SPaul Chaignon DUMP_XLATED, 77ec202509SPaul Chaignon }; 78ec202509SPaul Chaignon 79b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 80b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 81b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 82a7ba4558SCong Wang [BPF_SK_SKB_VERDICT] = "skb_verdict", 83b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 84092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 85b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 86b7d3826cSJohn Fastabend }; 87b7d3826cSJohn Fastabend 888f184732SQuentin Monnet static struct hashmap *prog_table; 8946241271SQuentin Monnet 90c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 91b7d3826cSJohn Fastabend { 92b7d3826cSJohn Fastabend enum bpf_attach_type type; 93b7d3826cSJohn Fastabend 94b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 95b7d3826cSJohn Fastabend if (attach_type_strings[type] && 96b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 97b7d3826cSJohn Fastabend return type; 98b7d3826cSJohn Fastabend } 99b7d3826cSJohn Fastabend 100b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 101b7d3826cSJohn Fastabend } 102b7d3826cSJohn Fastabend 103*c59765cfSDave Marchevsky static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 104*c59765cfSDave Marchevsky void **info_data, size_t *const info_data_sz) 105*c59765cfSDave Marchevsky { 106*c59765cfSDave Marchevsky struct bpf_prog_info holder = {}; 107*c59765cfSDave Marchevsky size_t needed = 0; 108*c59765cfSDave Marchevsky void *ptr; 109*c59765cfSDave Marchevsky 110*c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 111*c59765cfSDave Marchevsky holder.jited_prog_len = info->jited_prog_len; 112*c59765cfSDave Marchevsky needed += info->jited_prog_len; 113*c59765cfSDave Marchevsky } else { 114*c59765cfSDave Marchevsky holder.xlated_prog_len = info->xlated_prog_len; 115*c59765cfSDave Marchevsky needed += info->xlated_prog_len; 116*c59765cfSDave Marchevsky } 117*c59765cfSDave Marchevsky 118*c59765cfSDave Marchevsky holder.nr_jited_ksyms = info->nr_jited_ksyms; 119*c59765cfSDave Marchevsky needed += info->nr_jited_ksyms * sizeof(__u64); 120*c59765cfSDave Marchevsky 121*c59765cfSDave Marchevsky holder.nr_jited_func_lens = info->nr_jited_func_lens; 122*c59765cfSDave Marchevsky needed += info->nr_jited_func_lens * sizeof(__u32); 123*c59765cfSDave Marchevsky 124*c59765cfSDave Marchevsky holder.nr_func_info = info->nr_func_info; 125*c59765cfSDave Marchevsky holder.func_info_rec_size = info->func_info_rec_size; 126*c59765cfSDave Marchevsky needed += info->nr_func_info * info->func_info_rec_size; 127*c59765cfSDave Marchevsky 128*c59765cfSDave Marchevsky holder.nr_line_info = info->nr_line_info; 129*c59765cfSDave Marchevsky holder.line_info_rec_size = info->line_info_rec_size; 130*c59765cfSDave Marchevsky needed += info->nr_line_info * info->line_info_rec_size; 131*c59765cfSDave Marchevsky 132*c59765cfSDave Marchevsky holder.nr_jited_line_info = info->nr_jited_line_info; 133*c59765cfSDave Marchevsky holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 134*c59765cfSDave Marchevsky needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 135*c59765cfSDave Marchevsky 136*c59765cfSDave Marchevsky if (needed > *info_data_sz) { 137*c59765cfSDave Marchevsky ptr = realloc(*info_data, needed); 138*c59765cfSDave Marchevsky if (!ptr) 139*c59765cfSDave Marchevsky return -1; 140*c59765cfSDave Marchevsky 141*c59765cfSDave Marchevsky *info_data = ptr; 142*c59765cfSDave Marchevsky *info_data_sz = needed; 143*c59765cfSDave Marchevsky } 144*c59765cfSDave Marchevsky ptr = *info_data; 145*c59765cfSDave Marchevsky 146*c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 147*c59765cfSDave Marchevsky holder.jited_prog_insns = ptr_to_u64(ptr); 148*c59765cfSDave Marchevsky ptr += holder.jited_prog_len; 149*c59765cfSDave Marchevsky } else { 150*c59765cfSDave Marchevsky holder.xlated_prog_insns = ptr_to_u64(ptr); 151*c59765cfSDave Marchevsky ptr += holder.xlated_prog_len; 152*c59765cfSDave Marchevsky } 153*c59765cfSDave Marchevsky 154*c59765cfSDave Marchevsky holder.jited_ksyms = ptr_to_u64(ptr); 155*c59765cfSDave Marchevsky ptr += holder.nr_jited_ksyms * sizeof(__u64); 156*c59765cfSDave Marchevsky 157*c59765cfSDave Marchevsky holder.jited_func_lens = ptr_to_u64(ptr); 158*c59765cfSDave Marchevsky ptr += holder.nr_jited_func_lens * sizeof(__u32); 159*c59765cfSDave Marchevsky 160*c59765cfSDave Marchevsky holder.func_info = ptr_to_u64(ptr); 161*c59765cfSDave Marchevsky ptr += holder.nr_func_info * holder.func_info_rec_size; 162*c59765cfSDave Marchevsky 163*c59765cfSDave Marchevsky holder.line_info = ptr_to_u64(ptr); 164*c59765cfSDave Marchevsky ptr += holder.nr_line_info * holder.line_info_rec_size; 165*c59765cfSDave Marchevsky 166*c59765cfSDave Marchevsky holder.jited_line_info = ptr_to_u64(ptr); 167*c59765cfSDave Marchevsky ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 168*c59765cfSDave Marchevsky 169*c59765cfSDave Marchevsky *info = holder; 170*c59765cfSDave Marchevsky return 0; 171*c59765cfSDave Marchevsky } 172*c59765cfSDave Marchevsky 17371bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 17471bb428fSJakub Kicinski { 17571bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 17671bb428fSJakub Kicinski time_t wallclock_secs; 17771bb428fSJakub Kicinski struct tm load_tm; 17871bb428fSJakub Kicinski 17971bb428fSJakub Kicinski buf[--size] = '\0'; 18071bb428fSJakub Kicinski 18171bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 18271bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 18371bb428fSJakub Kicinski perror("Can't read clocks"); 18471bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 18571bb428fSJakub Kicinski return; 18671bb428fSJakub Kicinski } 18771bb428fSJakub Kicinski 18871bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 18907480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 19007480cbcSJakub Kicinski 1000000000; 19107480cbcSJakub Kicinski 19271bb428fSJakub Kicinski 19371bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 19471bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 19571bb428fSJakub Kicinski return; 19671bb428fSJakub Kicinski } 19771bb428fSJakub Kicinski 198a3fe1f6fSQuentin Monnet if (json_output) 199a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 200a3fe1f6fSQuentin Monnet else 201a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 20271bb428fSJakub Kicinski } 20371bb428fSJakub Kicinski 2046e7e034eSQuentin Monnet static void show_prog_maps(int fd, __u32 num_maps) 20571bb428fSJakub Kicinski { 20671bb428fSJakub Kicinski struct bpf_prog_info info = {}; 20771bb428fSJakub Kicinski __u32 len = sizeof(info); 20871bb428fSJakub Kicinski __u32 map_ids[num_maps]; 20971bb428fSJakub Kicinski unsigned int i; 21071bb428fSJakub Kicinski int err; 21171bb428fSJakub Kicinski 21271bb428fSJakub Kicinski info.nr_map_ids = num_maps; 21371bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 21471bb428fSJakub Kicinski 21571bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 21671bb428fSJakub Kicinski if (err || !info.nr_map_ids) 21771bb428fSJakub Kicinski return; 21871bb428fSJakub Kicinski 219743cc665SQuentin Monnet if (json_output) { 220743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 221743cc665SQuentin Monnet jsonw_start_array(json_wtr); 222743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 223743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 224743cc665SQuentin Monnet jsonw_end_array(json_wtr); 225743cc665SQuentin Monnet } else { 22671bb428fSJakub Kicinski printf(" map_ids "); 22771bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 22871bb428fSJakub Kicinski printf("%u%s", map_ids[i], 22971bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 23071bb428fSJakub Kicinski } 23171bb428fSJakub Kicinski } 23271bb428fSJakub Kicinski 233aff52e68SYiFei Zhu static void *find_metadata(int prog_fd, struct bpf_map_info *map_info) 234aff52e68SYiFei Zhu { 235aff52e68SYiFei Zhu struct bpf_prog_info prog_info; 236aff52e68SYiFei Zhu __u32 prog_info_len; 237aff52e68SYiFei Zhu __u32 map_info_len; 238aff52e68SYiFei Zhu void *value = NULL; 239aff52e68SYiFei Zhu __u32 *map_ids; 240aff52e68SYiFei Zhu int nr_maps; 241aff52e68SYiFei Zhu int key = 0; 242aff52e68SYiFei Zhu int map_fd; 243aff52e68SYiFei Zhu int ret; 244aff52e68SYiFei Zhu __u32 i; 245aff52e68SYiFei Zhu 246aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 247aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 248aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 249aff52e68SYiFei Zhu if (ret) 250aff52e68SYiFei Zhu return NULL; 251aff52e68SYiFei Zhu 252aff52e68SYiFei Zhu if (!prog_info.nr_map_ids) 253aff52e68SYiFei Zhu return NULL; 254aff52e68SYiFei Zhu 255aff52e68SYiFei Zhu map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); 256aff52e68SYiFei Zhu if (!map_ids) 257aff52e68SYiFei Zhu return NULL; 258aff52e68SYiFei Zhu 259aff52e68SYiFei Zhu nr_maps = prog_info.nr_map_ids; 260aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 261aff52e68SYiFei Zhu prog_info.nr_map_ids = nr_maps; 262aff52e68SYiFei Zhu prog_info.map_ids = ptr_to_u64(map_ids); 263aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 264aff52e68SYiFei Zhu 265aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 266aff52e68SYiFei Zhu if (ret) 267aff52e68SYiFei Zhu goto free_map_ids; 268aff52e68SYiFei Zhu 269aff52e68SYiFei Zhu for (i = 0; i < prog_info.nr_map_ids; i++) { 270aff52e68SYiFei Zhu map_fd = bpf_map_get_fd_by_id(map_ids[i]); 271aff52e68SYiFei Zhu if (map_fd < 0) 272aff52e68SYiFei Zhu goto free_map_ids; 273aff52e68SYiFei Zhu 274aff52e68SYiFei Zhu memset(map_info, 0, sizeof(*map_info)); 275aff52e68SYiFei Zhu map_info_len = sizeof(*map_info); 276aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(map_fd, map_info, &map_info_len); 277aff52e68SYiFei Zhu if (ret < 0) { 278aff52e68SYiFei Zhu close(map_fd); 279aff52e68SYiFei Zhu goto free_map_ids; 280aff52e68SYiFei Zhu } 281aff52e68SYiFei Zhu 282aff52e68SYiFei Zhu if (map_info->type != BPF_MAP_TYPE_ARRAY || 283aff52e68SYiFei Zhu map_info->key_size != sizeof(int) || 284aff52e68SYiFei Zhu map_info->max_entries != 1 || 285aff52e68SYiFei Zhu !map_info->btf_value_type_id || 286aff52e68SYiFei Zhu !strstr(map_info->name, ".rodata")) { 287aff52e68SYiFei Zhu close(map_fd); 288aff52e68SYiFei Zhu continue; 289aff52e68SYiFei Zhu } 290aff52e68SYiFei Zhu 291aff52e68SYiFei Zhu value = malloc(map_info->value_size); 292aff52e68SYiFei Zhu if (!value) { 293aff52e68SYiFei Zhu close(map_fd); 294aff52e68SYiFei Zhu goto free_map_ids; 295aff52e68SYiFei Zhu } 296aff52e68SYiFei Zhu 297aff52e68SYiFei Zhu if (bpf_map_lookup_elem(map_fd, &key, value)) { 298aff52e68SYiFei Zhu close(map_fd); 299aff52e68SYiFei Zhu free(value); 300aff52e68SYiFei Zhu value = NULL; 301aff52e68SYiFei Zhu goto free_map_ids; 302aff52e68SYiFei Zhu } 303aff52e68SYiFei Zhu 304aff52e68SYiFei Zhu close(map_fd); 305aff52e68SYiFei Zhu break; 306aff52e68SYiFei Zhu } 307aff52e68SYiFei Zhu 308aff52e68SYiFei Zhu free_map_ids: 309aff52e68SYiFei Zhu free(map_ids); 310aff52e68SYiFei Zhu return value; 311aff52e68SYiFei Zhu } 312aff52e68SYiFei Zhu 313aff52e68SYiFei Zhu static bool has_metadata_prefix(const char *s) 314aff52e68SYiFei Zhu { 315aff52e68SYiFei Zhu return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0; 316aff52e68SYiFei Zhu } 317aff52e68SYiFei Zhu 318aff52e68SYiFei Zhu static void show_prog_metadata(int fd, __u32 num_maps) 319aff52e68SYiFei Zhu { 320aff52e68SYiFei Zhu const struct btf_type *t_datasec, *t_var; 321aff52e68SYiFei Zhu struct bpf_map_info map_info; 322aff52e68SYiFei Zhu struct btf_var_secinfo *vsi; 323aff52e68SYiFei Zhu bool printed_header = false; 324aff52e68SYiFei Zhu unsigned int i, vlen; 325aff52e68SYiFei Zhu void *value = NULL; 326aff52e68SYiFei Zhu const char *name; 32786f4b7f2SQuentin Monnet struct btf *btf; 328aff52e68SYiFei Zhu int err; 329aff52e68SYiFei Zhu 330aff52e68SYiFei Zhu if (!num_maps) 331aff52e68SYiFei Zhu return; 332aff52e68SYiFei Zhu 333aff52e68SYiFei Zhu memset(&map_info, 0, sizeof(map_info)); 334aff52e68SYiFei Zhu value = find_metadata(fd, &map_info); 335aff52e68SYiFei Zhu if (!value) 336aff52e68SYiFei Zhu return; 337aff52e68SYiFei Zhu 33886f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(map_info.btf_id); 33986f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) 340aff52e68SYiFei Zhu goto out_free; 341aff52e68SYiFei Zhu 342aff52e68SYiFei Zhu t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); 343aff52e68SYiFei Zhu if (!btf_is_datasec(t_datasec)) 344aff52e68SYiFei Zhu goto out_free; 345aff52e68SYiFei Zhu 346aff52e68SYiFei Zhu vlen = btf_vlen(t_datasec); 347aff52e68SYiFei Zhu vsi = btf_var_secinfos(t_datasec); 348aff52e68SYiFei Zhu 349aff52e68SYiFei Zhu /* We don't proceed to check the kinds of the elements of the DATASEC. 350aff52e68SYiFei Zhu * The verifier enforces them to be BTF_KIND_VAR. 351aff52e68SYiFei Zhu */ 352aff52e68SYiFei Zhu 353aff52e68SYiFei Zhu if (json_output) { 354aff52e68SYiFei Zhu struct btf_dumper d = { 355aff52e68SYiFei Zhu .btf = btf, 356aff52e68SYiFei Zhu .jw = json_wtr, 357aff52e68SYiFei Zhu .is_plain_text = false, 358aff52e68SYiFei Zhu }; 359aff52e68SYiFei Zhu 360aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 361aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 362aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 363aff52e68SYiFei Zhu 364aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 365aff52e68SYiFei Zhu continue; 366aff52e68SYiFei Zhu 367aff52e68SYiFei Zhu if (!printed_header) { 368aff52e68SYiFei Zhu jsonw_name(json_wtr, "metadata"); 369aff52e68SYiFei Zhu jsonw_start_object(json_wtr); 370aff52e68SYiFei Zhu printed_header = true; 371aff52e68SYiFei Zhu } 372aff52e68SYiFei Zhu 373aff52e68SYiFei Zhu jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); 374aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 375aff52e68SYiFei Zhu if (err) { 376aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 377aff52e68SYiFei Zhu break; 378aff52e68SYiFei Zhu } 379aff52e68SYiFei Zhu } 380aff52e68SYiFei Zhu if (printed_header) 381aff52e68SYiFei Zhu jsonw_end_object(json_wtr); 382aff52e68SYiFei Zhu } else { 383e89ef634SQuentin Monnet json_writer_t *btf_wtr; 384aff52e68SYiFei Zhu struct btf_dumper d = { 385aff52e68SYiFei Zhu .btf = btf, 386aff52e68SYiFei Zhu .is_plain_text = true, 387aff52e68SYiFei Zhu }; 388aff52e68SYiFei Zhu 389aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 390aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 391aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 392aff52e68SYiFei Zhu 393aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 394aff52e68SYiFei Zhu continue; 395aff52e68SYiFei Zhu 396aff52e68SYiFei Zhu if (!printed_header) { 397aff52e68SYiFei Zhu printf("\tmetadata:"); 398e89ef634SQuentin Monnet 399e89ef634SQuentin Monnet btf_wtr = jsonw_new(stdout); 400e89ef634SQuentin Monnet if (!btf_wtr) { 401e89ef634SQuentin Monnet p_err("jsonw alloc failed"); 402e89ef634SQuentin Monnet goto out_free; 403e89ef634SQuentin Monnet } 404e89ef634SQuentin Monnet d.jw = btf_wtr, 405e89ef634SQuentin Monnet 406aff52e68SYiFei Zhu printed_header = true; 407aff52e68SYiFei Zhu } 408aff52e68SYiFei Zhu 409aff52e68SYiFei Zhu printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); 410aff52e68SYiFei Zhu 411aff52e68SYiFei Zhu jsonw_reset(btf_wtr); 412aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 413aff52e68SYiFei Zhu if (err) { 414aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 415aff52e68SYiFei Zhu break; 416aff52e68SYiFei Zhu } 417aff52e68SYiFei Zhu } 418aff52e68SYiFei Zhu if (printed_header) 419aff52e68SYiFei Zhu jsonw_destroy(&btf_wtr); 420aff52e68SYiFei Zhu } 421aff52e68SYiFei Zhu 422aff52e68SYiFei Zhu out_free: 423aff52e68SYiFei Zhu btf__free(btf); 424aff52e68SYiFei Zhu free(value); 425aff52e68SYiFei Zhu } 426aff52e68SYiFei Zhu 427ec202509SPaul Chaignon static void print_prog_header_json(struct bpf_prog_info *info) 428743cc665SQuentin Monnet { 429743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 430743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 431743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 432743cc665SQuentin Monnet prog_type_name[info->type]); 43371bb428fSJakub Kicinski else 434743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 43571bb428fSJakub Kicinski 436743cc665SQuentin Monnet if (*info->name) 437743cc665SQuentin Monnet jsonw_string_field(json_wtr, "name", info->name); 43871bb428fSJakub Kicinski 439743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 440743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 441743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 442743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 44371bb428fSJakub Kicinski 4449b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 44588ad472bSAlexei Starovoitov if (info->run_time_ns) { 44688ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 44788ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 44888ad472bSAlexei Starovoitov } 4499ed9e9baSAlexei Starovoitov if (info->recursion_misses) 4509ed9e9baSAlexei Starovoitov jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 451ec202509SPaul Chaignon } 4529b984a20SJiri Olsa 453ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 454ec202509SPaul Chaignon { 455ec202509SPaul Chaignon char *memlock; 456ec202509SPaul Chaignon 457ec202509SPaul Chaignon jsonw_start_object(json_wtr); 458ec202509SPaul Chaignon print_prog_header_json(info); 45952262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 46052262210SJakub Kicinski 461743cc665SQuentin Monnet if (info->load_time) { 46271bb428fSJakub Kicinski char buf[32]; 46371bb428fSJakub Kicinski 464743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 46571bb428fSJakub Kicinski 46671bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 467a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 468a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 469743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 47071bb428fSJakub Kicinski } 47171bb428fSJakub Kicinski 472743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 47371bb428fSJakub Kicinski 474743cc665SQuentin Monnet if (info->jited_prog_len) { 475743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 476743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 477743cc665SQuentin Monnet } else { 478743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 479743cc665SQuentin Monnet } 480743cc665SQuentin Monnet 481743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 482743cc665SQuentin Monnet if (memlock) 483743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 484743cc665SQuentin Monnet free(memlock); 485743cc665SQuentin Monnet 486743cc665SQuentin Monnet if (info->nr_map_ids) 487743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 488743cc665SQuentin Monnet 489569b0c77SPrashant Bhole if (info->btf_id) 490569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 491569b0c77SPrashant Bhole 4928f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 4938f184732SQuentin Monnet struct hashmap_entry *entry; 4944990f1f4SPrashant Bhole 4954990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 4964990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 4978f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 4988f184732SQuentin Monnet u32_as_hash_field(info->id)) 4998f184732SQuentin Monnet jsonw_string(json_wtr, entry->value); 5004990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 5014990f1f4SPrashant Bhole } 5024990f1f4SPrashant Bhole 503d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 504d53dee3fSAndrii Nakryiko 505aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 506aff52e68SYiFei Zhu 507743cc665SQuentin Monnet jsonw_end_object(json_wtr); 508743cc665SQuentin Monnet } 509743cc665SQuentin Monnet 510ec202509SPaul Chaignon static void print_prog_header_plain(struct bpf_prog_info *info) 511743cc665SQuentin Monnet { 512743cc665SQuentin Monnet printf("%u: ", info->id); 513743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 514743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 515743cc665SQuentin Monnet else 516743cc665SQuentin Monnet printf("type %u ", info->type); 517743cc665SQuentin Monnet 518743cc665SQuentin Monnet if (*info->name) 519743cc665SQuentin Monnet printf("name %s ", info->name); 520743cc665SQuentin Monnet 521743cc665SQuentin Monnet printf("tag "); 522743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 52352262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5249b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 52588ad472bSAlexei Starovoitov if (info->run_time_ns) 52688ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 52788ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5289ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5299ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 530743cc665SQuentin Monnet printf("\n"); 531ec202509SPaul Chaignon } 532ec202509SPaul Chaignon 533ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 534ec202509SPaul Chaignon { 535ec202509SPaul Chaignon char *memlock; 536ec202509SPaul Chaignon 537ec202509SPaul Chaignon print_prog_header_plain(info); 538743cc665SQuentin Monnet 539743cc665SQuentin Monnet if (info->load_time) { 540743cc665SQuentin Monnet char buf[32]; 541743cc665SQuentin Monnet 542743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 543743cc665SQuentin Monnet 544743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 545743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 546743cc665SQuentin Monnet } 547743cc665SQuentin Monnet 548743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 549743cc665SQuentin Monnet 550743cc665SQuentin Monnet if (info->jited_prog_len) 551743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 55271bb428fSJakub Kicinski else 55371bb428fSJakub Kicinski printf(" not jited"); 55471bb428fSJakub Kicinski 55571bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 55671bb428fSJakub Kicinski if (memlock) 55771bb428fSJakub Kicinski printf(" memlock %sB", memlock); 55871bb428fSJakub Kicinski free(memlock); 55971bb428fSJakub Kicinski 560743cc665SQuentin Monnet if (info->nr_map_ids) 561743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 56271bb428fSJakub Kicinski 5638f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5648f184732SQuentin Monnet struct hashmap_entry *entry; 5654990f1f4SPrashant Bhole 5668f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 5678f184732SQuentin Monnet u32_as_hash_field(info->id)) 5688f184732SQuentin Monnet printf("\n\tpinned %s", (char *)entry->value); 5694990f1f4SPrashant Bhole } 5704990f1f4SPrashant Bhole 571569b0c77SPrashant Bhole if (info->btf_id) 572031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 573569b0c77SPrashant Bhole 574d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 575d53dee3fSAndrii Nakryiko 57671bb428fSJakub Kicinski printf("\n"); 577aff52e68SYiFei Zhu 578aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 579743cc665SQuentin Monnet } 580743cc665SQuentin Monnet 581743cc665SQuentin Monnet static int show_prog(int fd) 582743cc665SQuentin Monnet { 583743cc665SQuentin Monnet struct bpf_prog_info info = {}; 584743cc665SQuentin Monnet __u32 len = sizeof(info); 585743cc665SQuentin Monnet int err; 586743cc665SQuentin Monnet 587743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 588743cc665SQuentin Monnet if (err) { 5899a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 590743cc665SQuentin Monnet return -1; 591743cc665SQuentin Monnet } 592743cc665SQuentin Monnet 593743cc665SQuentin Monnet if (json_output) 594743cc665SQuentin Monnet print_prog_json(&info, fd); 595743cc665SQuentin Monnet else 596743cc665SQuentin Monnet print_prog_plain(&info, fd); 59771bb428fSJakub Kicinski 59871bb428fSJakub Kicinski return 0; 59971bb428fSJakub Kicinski } 60071bb428fSJakub Kicinski 601ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 602ec202509SPaul Chaignon { 603ec202509SPaul Chaignon int *fds = NULL; 604ec202509SPaul Chaignon int nb_fds, i; 605ec202509SPaul Chaignon int err = -1; 606ec202509SPaul Chaignon 607ec202509SPaul Chaignon fds = malloc(sizeof(int)); 608ec202509SPaul Chaignon if (!fds) { 609ec202509SPaul Chaignon p_err("mem alloc failed"); 610ec202509SPaul Chaignon return -1; 611ec202509SPaul Chaignon } 612ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 613ec202509SPaul Chaignon if (nb_fds < 1) 614ec202509SPaul Chaignon goto exit_free; 615ec202509SPaul Chaignon 616ec202509SPaul Chaignon if (json_output && nb_fds > 1) 617ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 618ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 619ec202509SPaul Chaignon err = show_prog(fds[i]); 620ec202509SPaul Chaignon if (err) { 621ec202509SPaul Chaignon for (; i < nb_fds; i++) 622ec202509SPaul Chaignon close(fds[i]); 623ec202509SPaul Chaignon break; 624ec202509SPaul Chaignon } 625ec202509SPaul Chaignon close(fds[i]); 626ec202509SPaul Chaignon } 627ec202509SPaul Chaignon if (json_output && nb_fds > 1) 628ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 629ec202509SPaul Chaignon 630ec202509SPaul Chaignon exit_free: 631ec202509SPaul Chaignon free(fds); 632ec202509SPaul Chaignon return err; 633ec202509SPaul Chaignon } 634ec202509SPaul Chaignon 63571bb428fSJakub Kicinski static int do_show(int argc, char **argv) 636743cc665SQuentin Monnet { 637743cc665SQuentin Monnet __u32 id = 0; 63871bb428fSJakub Kicinski int err; 63971bb428fSJakub Kicinski int fd; 64071bb428fSJakub Kicinski 64146241271SQuentin Monnet if (show_pinned) { 6428f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6438f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 6448f184732SQuentin Monnet if (!prog_table) { 6458f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6468f184732SQuentin Monnet return -1; 6478f184732SQuentin Monnet } 6488f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 64946241271SQuentin Monnet } 650d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6514990f1f4SPrashant Bhole 652ec202509SPaul Chaignon if (argc == 2) 653ec202509SPaul Chaignon return do_show_subset(argc, argv); 65471bb428fSJakub Kicinski 65571bb428fSJakub Kicinski if (argc) 65671bb428fSJakub Kicinski return BAD_ARG(); 65771bb428fSJakub Kicinski 658743cc665SQuentin Monnet if (json_output) 659743cc665SQuentin Monnet jsonw_start_array(json_wtr); 66071bb428fSJakub Kicinski while (true) { 66171bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 66271bb428fSJakub Kicinski if (err) { 6631739c26dSQuentin Monnet if (errno == ENOENT) { 6641739c26dSQuentin Monnet err = 0; 66571bb428fSJakub Kicinski break; 6661739c26dSQuentin Monnet } 6679a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6689a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 669743cc665SQuentin Monnet err = -1; 670743cc665SQuentin Monnet break; 67171bb428fSJakub Kicinski } 67271bb428fSJakub Kicinski 67371bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 67471bb428fSJakub Kicinski if (fd < 0) { 6758207c6ddSJakub Kicinski if (errno == ENOENT) 6768207c6ddSJakub Kicinski continue; 6779a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 67871bb428fSJakub Kicinski id, strerror(errno)); 679743cc665SQuentin Monnet err = -1; 680743cc665SQuentin Monnet break; 68171bb428fSJakub Kicinski } 68271bb428fSJakub Kicinski 68371bb428fSJakub Kicinski err = show_prog(fd); 68471bb428fSJakub Kicinski close(fd); 68571bb428fSJakub Kicinski if (err) 686743cc665SQuentin Monnet break; 68771bb428fSJakub Kicinski } 68871bb428fSJakub Kicinski 689743cc665SQuentin Monnet if (json_output) 690743cc665SQuentin Monnet jsonw_end_array(json_wtr); 691743cc665SQuentin Monnet 692d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 693d53dee3fSAndrii Nakryiko 69446241271SQuentin Monnet if (show_pinned) 6958f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 69646241271SQuentin Monnet 697743cc665SQuentin Monnet return err; 69871bb428fSJakub Kicinski } 69971bb428fSJakub Kicinski 700ec202509SPaul Chaignon static int 701ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 702ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 70371bb428fSJakub Kicinski { 704b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 7053ddeac67SJakub Kicinski const char *disasm_opt = NULL; 7067105e828SDaniel Borkmann struct dump_data dd = {}; 707cae73f23SSong Liu void *func_info = NULL; 708254471e5SYonghong Song struct btf *btf = NULL; 709254471e5SYonghong Song char func_sig[1024]; 71071bb428fSJakub Kicinski unsigned char *buf; 711cae73f23SSong Liu __u32 member_len; 71271bb428fSJakub Kicinski ssize_t n; 71371bb428fSJakub Kicinski int fd; 71471bb428fSJakub Kicinski 715cae73f23SSong Liu if (mode == DUMP_JITED) { 7165b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 7179a5ab8bfSQuentin Monnet p_info("no instructions returned"); 718ec202509SPaul Chaignon return -1; 719f84192eeSSandipan Das } 72009f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 721cae73f23SSong Liu member_len = info->jited_prog_len; 722cae73f23SSong Liu } else { /* DUMP_XLATED */ 723d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7247105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 725ec202509SPaul Chaignon return -1; 7267105e828SDaniel Borkmann } 72709f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 728cae73f23SSong Liu member_len = info->xlated_prog_len; 729cae73f23SSong Liu } 7307105e828SDaniel Borkmann 73186f4b7f2SQuentin Monnet if (info->btf_id) { 73286f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 73386f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 734254471e5SYonghong Song p_err("failed to get btf"); 735ec202509SPaul Chaignon return -1; 736254471e5SYonghong Song } 73786f4b7f2SQuentin Monnet } 738254471e5SYonghong Song 73909f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 740cae73f23SSong Liu 741cae73f23SSong Liu if (info->nr_line_info) { 742cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 743b053b439SMartin KaFai Lau if (!prog_linfo) 74410a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 745b053b439SMartin KaFai Lau } 746b053b439SMartin KaFai Lau 74771bb428fSJakub Kicinski if (filepath) { 74871bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 74971bb428fSJakub Kicinski if (fd < 0) { 7509a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 75171bb428fSJakub Kicinski strerror(errno)); 752ec202509SPaul Chaignon return -1; 75371bb428fSJakub Kicinski } 75471bb428fSJakub Kicinski 755cae73f23SSong Liu n = write(fd, buf, member_len); 75671bb428fSJakub Kicinski close(fd); 75709f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7589a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 75971bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 760ec202509SPaul Chaignon return -1; 76171bb428fSJakub Kicinski } 76252c84d36SQuentin Monnet 76352c84d36SQuentin Monnet if (json_output) 76452c84d36SQuentin Monnet jsonw_null(json_wtr); 765cae73f23SSong Liu } else if (mode == DUMP_JITED) { 766e6593596SJiong Wang const char *name = NULL; 767e6593596SJiong Wang 768cae73f23SSong Liu if (info->ifindex) { 769cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 770cae73f23SSong Liu info->netns_dev, 771cae73f23SSong Liu info->netns_ino, 7723ddeac67SJakub Kicinski &disasm_opt); 773e6593596SJiong Wang if (!name) 774ec202509SPaul Chaignon return -1; 775e6593596SJiong Wang } 776e6593596SJiong Wang 777cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 778f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 779254471e5SYonghong Song struct bpf_func_info *record; 780f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 781f7f62c71SSandipan Das unsigned char *img = buf; 782f7f62c71SSandipan Das __u64 *ksyms = NULL; 783f7f62c71SSandipan Das __u32 *lens; 784f7f62c71SSandipan Das __u32 i; 785cae73f23SSong Liu if (info->nr_jited_ksyms) { 786f7f62c71SSandipan Das kernel_syms_load(&dd); 78709f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 788f7f62c71SSandipan Das } 789f7f62c71SSandipan Das 790f7f62c71SSandipan Das if (json_output) 791f7f62c71SSandipan Das jsonw_start_array(json_wtr); 792f7f62c71SSandipan Das 79309f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 794cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 795f7f62c71SSandipan Das if (ksyms) { 796f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 797f7f62c71SSandipan Das if (sym) 798f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 799f7f62c71SSandipan Das else 800f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 801f7f62c71SSandipan Das } else { 802f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 803f7f62c71SSandipan Das } 804f7f62c71SSandipan Das 805254471e5SYonghong Song if (func_info) { 806cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 807254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 808254471e5SYonghong Song func_sig, 809254471e5SYonghong Song sizeof(func_sig)); 810254471e5SYonghong Song } 811254471e5SYonghong Song 812f7f62c71SSandipan Das if (json_output) { 813f7f62c71SSandipan Das jsonw_start_object(json_wtr); 814254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 815254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 816254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 817254471e5SYonghong Song } 818f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 819f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 820f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 821f7f62c71SSandipan Das } else { 822254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 823254471e5SYonghong Song printf("%s:\n", func_sig); 824f7f62c71SSandipan Das printf("%s:\n", sym_name); 825f7f62c71SSandipan Das } 826f7f62c71SSandipan Das 827b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 828b053b439SMartin KaFai Lau name, disasm_opt, btf, 829b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 830b053b439SMartin KaFai Lau linum); 831b053b439SMartin KaFai Lau 832f7f62c71SSandipan Das img += lens[i]; 833f7f62c71SSandipan Das 834f7f62c71SSandipan Das if (json_output) 835f7f62c71SSandipan Das jsonw_end_object(json_wtr); 836f7f62c71SSandipan Das else 837f7f62c71SSandipan Das printf("\n"); 838f7f62c71SSandipan Das } 839f7f62c71SSandipan Das 840f7f62c71SSandipan Das if (json_output) 841f7f62c71SSandipan Das jsonw_end_array(json_wtr); 842f7f62c71SSandipan Das } else { 843cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 844b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 845f7f62c71SSandipan Das } 846b6c1cedbSJiong Wang } else if (visual) { 847b6c1cedbSJiong Wang if (json_output) 848b6c1cedbSJiong Wang jsonw_null(json_wtr); 849b6c1cedbSJiong Wang else 850cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 8517105e828SDaniel Borkmann } else { 8527105e828SDaniel Borkmann kernel_syms_load(&dd); 853cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 85409f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 855254471e5SYonghong Song dd.btf = btf; 856254471e5SYonghong Song dd.func_info = func_info; 857cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 858b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 859f84192eeSSandipan Das 860f05e2c32SQuentin Monnet if (json_output) 861cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 862b053b439SMartin KaFai Lau linum); 863f05e2c32SQuentin Monnet else 864cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 865b053b439SMartin KaFai Lau linum); 8667105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8677105e828SDaniel Borkmann } 86871bb428fSJakub Kicinski 869369e955bSQuentin Monnet btf__free(btf); 870369e955bSQuentin Monnet 87171bb428fSJakub Kicinski return 0; 872ec202509SPaul Chaignon } 87371bb428fSJakub Kicinski 874ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 875ec202509SPaul Chaignon { 876*c59765cfSDave Marchevsky struct bpf_prog_info info; 877*c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 878*c59765cfSDave Marchevsky size_t info_data_sz = 0; 879*c59765cfSDave Marchevsky void *info_data = NULL; 880ec202509SPaul Chaignon char *filepath = NULL; 881ec202509SPaul Chaignon bool opcodes = false; 882ec202509SPaul Chaignon bool visual = false; 883ec202509SPaul Chaignon enum dump_mode mode; 884ec202509SPaul Chaignon bool linum = false; 885ec202509SPaul Chaignon int nb_fds, i = 0; 886*c59765cfSDave Marchevsky int *fds = NULL; 887ec202509SPaul Chaignon int err = -1; 888ec202509SPaul Chaignon 889ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 890ec202509SPaul Chaignon if (disasm_init()) 89171bb428fSJakub Kicinski return -1; 892ec202509SPaul Chaignon mode = DUMP_JITED; 893ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 894ec202509SPaul Chaignon mode = DUMP_XLATED; 895ec202509SPaul Chaignon } else { 896ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 897ec202509SPaul Chaignon return -1; 898ec202509SPaul Chaignon } 899ec202509SPaul Chaignon NEXT_ARG(); 900ec202509SPaul Chaignon 901ec202509SPaul Chaignon if (argc < 2) 902ec202509SPaul Chaignon usage(); 903ec202509SPaul Chaignon 904ec202509SPaul Chaignon fds = malloc(sizeof(int)); 905ec202509SPaul Chaignon if (!fds) { 906ec202509SPaul Chaignon p_err("mem alloc failed"); 907ec202509SPaul Chaignon return -1; 908ec202509SPaul Chaignon } 909ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 910ec202509SPaul Chaignon if (nb_fds < 1) 911ec202509SPaul Chaignon goto exit_free; 912ec202509SPaul Chaignon 913ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 914ec202509SPaul Chaignon NEXT_ARG(); 915ec202509SPaul Chaignon if (!argc) { 916ec202509SPaul Chaignon p_err("expected file path"); 917ec202509SPaul Chaignon goto exit_close; 918ec202509SPaul Chaignon } 919ec202509SPaul Chaignon if (nb_fds > 1) { 920ec202509SPaul Chaignon p_err("several programs matched"); 921ec202509SPaul Chaignon goto exit_close; 922ec202509SPaul Chaignon } 923ec202509SPaul Chaignon 924ec202509SPaul Chaignon filepath = *argv; 925ec202509SPaul Chaignon NEXT_ARG(); 926ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 927ec202509SPaul Chaignon opcodes = true; 928ec202509SPaul Chaignon NEXT_ARG(); 929ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 930ec202509SPaul Chaignon if (nb_fds > 1) { 931ec202509SPaul Chaignon p_err("several programs matched"); 932ec202509SPaul Chaignon goto exit_close; 933ec202509SPaul Chaignon } 934ec202509SPaul Chaignon 935ec202509SPaul Chaignon visual = true; 936ec202509SPaul Chaignon NEXT_ARG(); 937ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 938ec202509SPaul Chaignon linum = true; 939ec202509SPaul Chaignon NEXT_ARG(); 940ec202509SPaul Chaignon } 941ec202509SPaul Chaignon 942ec202509SPaul Chaignon if (argc) { 943ec202509SPaul Chaignon usage(); 944ec202509SPaul Chaignon goto exit_close; 945ec202509SPaul Chaignon } 946ec202509SPaul Chaignon 947ec202509SPaul Chaignon if (json_output && nb_fds > 1) 948ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 949ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 950*c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 951*c59765cfSDave Marchevsky 952*c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 953*c59765cfSDave Marchevsky if (err) { 954*c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 955*c59765cfSDave Marchevsky break; 956*c59765cfSDave Marchevsky } 957*c59765cfSDave Marchevsky 958*c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 959*c59765cfSDave Marchevsky if (err) { 960*c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 961*c59765cfSDave Marchevsky break; 962*c59765cfSDave Marchevsky } 963*c59765cfSDave Marchevsky 964*c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 965*c59765cfSDave Marchevsky if (err) { 966ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 967ec202509SPaul Chaignon break; 968ec202509SPaul Chaignon } 969ec202509SPaul Chaignon 970ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 971ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 972*c59765cfSDave Marchevsky print_prog_header_json(&info); 973ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 974ec202509SPaul Chaignon } else if (nb_fds > 1) { 975*c59765cfSDave Marchevsky print_prog_header_plain(&info); 976ec202509SPaul Chaignon } 977ec202509SPaul Chaignon 978*c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 979ec202509SPaul Chaignon 980ec202509SPaul Chaignon if (json_output && nb_fds > 1) 981ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 982ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 983ec202509SPaul Chaignon printf("\n"); 984ec202509SPaul Chaignon 985ec202509SPaul Chaignon if (err) 986ec202509SPaul Chaignon break; 987ec202509SPaul Chaignon close(fds[i]); 988ec202509SPaul Chaignon } 989ec202509SPaul Chaignon if (json_output && nb_fds > 1) 990ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 991ec202509SPaul Chaignon 992ec202509SPaul Chaignon exit_close: 993ec202509SPaul Chaignon for (; i < nb_fds; i++) 994ec202509SPaul Chaignon close(fds[i]); 995ec202509SPaul Chaignon exit_free: 996*c59765cfSDave Marchevsky free(info_data); 997ec202509SPaul Chaignon free(fds); 998ec202509SPaul Chaignon return err; 99971bb428fSJakub Kicinski } 100071bb428fSJakub Kicinski 100171bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 100271bb428fSJakub Kicinski { 1003004b45c0SQuentin Monnet int err; 1004004b45c0SQuentin Monnet 100575a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 1006004b45c0SQuentin Monnet if (!err && json_output) 1007004b45c0SQuentin Monnet jsonw_null(json_wtr); 1008004b45c0SQuentin Monnet return err; 100971bb428fSJakub Kicinski } 101071bb428fSJakub Kicinski 10113ff5a4dcSJakub Kicinski struct map_replace { 10123ff5a4dcSJakub Kicinski int idx; 10133ff5a4dcSJakub Kicinski int fd; 10143ff5a4dcSJakub Kicinski char *name; 10153ff5a4dcSJakub Kicinski }; 10163ff5a4dcSJakub Kicinski 1017c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 10183ff5a4dcSJakub Kicinski { 10193ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10203ff5a4dcSJakub Kicinski 10213ff5a4dcSJakub Kicinski return a->idx - b->idx; 10223ff5a4dcSJakub Kicinski } 10233ff5a4dcSJakub Kicinski 1024092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1025092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1026092f0892SStanislav Fomichev int *mapfd) 1027092f0892SStanislav Fomichev { 1028092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1029092f0892SStanislav Fomichev return -EINVAL; 1030092f0892SStanislav Fomichev 1031092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1032092f0892SStanislav Fomichev if (*progfd < 0) 1033092f0892SStanislav Fomichev return *progfd; 1034092f0892SStanislav Fomichev 1035092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1036092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1037092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1038092f0892SStanislav Fomichev return -EINVAL; 1039092f0892SStanislav Fomichev } 1040092f0892SStanislav Fomichev 1041092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1042f9b7ff0dSLorenz Bauer *mapfd = 0; 1043092f0892SStanislav Fomichev return 0; 1044092f0892SStanislav Fomichev } 1045092f0892SStanislav Fomichev 1046092f0892SStanislav Fomichev NEXT_ARG(); 1047092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1048092f0892SStanislav Fomichev return -EINVAL; 1049092f0892SStanislav Fomichev 1050092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1051092f0892SStanislav Fomichev if (*mapfd < 0) 1052092f0892SStanislav Fomichev return *mapfd; 1053092f0892SStanislav Fomichev 1054092f0892SStanislav Fomichev return 0; 1055092f0892SStanislav Fomichev } 1056092f0892SStanislav Fomichev 1057b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1058b7d3826cSJohn Fastabend { 1059b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1060092f0892SStanislav Fomichev int err, progfd; 1061092f0892SStanislav Fomichev int mapfd; 1062b7d3826cSJohn Fastabend 1063092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1064092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1065092f0892SStanislav Fomichev if (err) 1066092f0892SStanislav Fomichev return err; 1067b7d3826cSJohn Fastabend 1068b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1069b7d3826cSJohn Fastabend if (err) { 1070b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1071b7d3826cSJohn Fastabend return -EINVAL; 1072b7d3826cSJohn Fastabend } 1073b7d3826cSJohn Fastabend 1074b7d3826cSJohn Fastabend if (json_output) 1075b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1076b7d3826cSJohn Fastabend return 0; 1077b7d3826cSJohn Fastabend } 1078b7d3826cSJohn Fastabend 1079b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1080b7d3826cSJohn Fastabend { 1081b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1082092f0892SStanislav Fomichev int err, progfd; 1083092f0892SStanislav Fomichev int mapfd; 1084b7d3826cSJohn Fastabend 1085092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1086092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1087092f0892SStanislav Fomichev if (err) 1088092f0892SStanislav Fomichev return err; 1089b7d3826cSJohn Fastabend 1090b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1091b7d3826cSJohn Fastabend if (err) { 1092b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1093b7d3826cSJohn Fastabend return -EINVAL; 1094b7d3826cSJohn Fastabend } 1095b7d3826cSJohn Fastabend 1096b7d3826cSJohn Fastabend if (json_output) 1097b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1098b7d3826cSJohn Fastabend return 0; 1099b7d3826cSJohn Fastabend } 110077380998SStanislav Fomichev 1101ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1102ba95c745SQuentin Monnet { 1103ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1104ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1105ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1106ba95c745SQuentin Monnet return -1; 1107ba95c745SQuentin Monnet } 1108ba95c745SQuentin Monnet 1109ba95c745SQuentin Monnet return 0; 1110ba95c745SQuentin Monnet } 1111ba95c745SQuentin Monnet 1112ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1113ba95c745SQuentin Monnet { 1114ba95c745SQuentin Monnet size_t block_size = 256; 1115ba95c745SQuentin Monnet size_t buf_size = block_size; 1116ba95c745SQuentin Monnet size_t nb_read = 0; 1117ba95c745SQuentin Monnet void *tmp; 1118ba95c745SQuentin Monnet FILE *f; 1119ba95c745SQuentin Monnet 1120ba95c745SQuentin Monnet if (!fname) { 1121ba95c745SQuentin Monnet *data_ptr = NULL; 1122ba95c745SQuentin Monnet *size = 0; 1123ba95c745SQuentin Monnet return 0; 1124ba95c745SQuentin Monnet } 1125ba95c745SQuentin Monnet 1126ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1127ba95c745SQuentin Monnet f = stdin; 1128ba95c745SQuentin Monnet else 1129ba95c745SQuentin Monnet f = fopen(fname, "r"); 1130ba95c745SQuentin Monnet if (!f) { 1131ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1132ba95c745SQuentin Monnet return -1; 1133ba95c745SQuentin Monnet } 1134ba95c745SQuentin Monnet 1135ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1136ba95c745SQuentin Monnet if (!*data_ptr) { 1137ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1138ba95c745SQuentin Monnet strerror(errno)); 1139ba95c745SQuentin Monnet goto err_fclose; 1140ba95c745SQuentin Monnet } 1141ba95c745SQuentin Monnet 1142ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1143ba95c745SQuentin Monnet if (feof(f)) 1144ba95c745SQuentin Monnet break; 1145ba95c745SQuentin Monnet if (ferror(f)) { 1146ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1147ba95c745SQuentin Monnet fname, strerror(errno)); 1148ba95c745SQuentin Monnet goto err_free; 1149ba95c745SQuentin Monnet } 1150ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1151ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1152ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1153ba95c745SQuentin Monnet UINT32_MAX); 1154ba95c745SQuentin Monnet goto err_free; 1155ba95c745SQuentin Monnet } 1156ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1157ba95c745SQuentin Monnet buf_size *= 2; 1158ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1159ba95c745SQuentin Monnet if (!tmp) { 1160ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1161ba95c745SQuentin Monnet strerror(errno)); 1162ba95c745SQuentin Monnet goto err_free; 1163ba95c745SQuentin Monnet } 1164ba95c745SQuentin Monnet *data_ptr = tmp; 1165ba95c745SQuentin Monnet } 1166ba95c745SQuentin Monnet } 1167ba95c745SQuentin Monnet if (f != stdin) 1168ba95c745SQuentin Monnet fclose(f); 1169ba95c745SQuentin Monnet 1170ba95c745SQuentin Monnet *size = nb_read; 1171ba95c745SQuentin Monnet return 0; 1172ba95c745SQuentin Monnet 1173ba95c745SQuentin Monnet err_free: 1174ba95c745SQuentin Monnet free(*data_ptr); 1175ba95c745SQuentin Monnet *data_ptr = NULL; 1176ba95c745SQuentin Monnet err_fclose: 1177ba95c745SQuentin Monnet if (f != stdin) 1178ba95c745SQuentin Monnet fclose(f); 1179ba95c745SQuentin Monnet return -1; 1180ba95c745SQuentin Monnet } 1181ba95c745SQuentin Monnet 1182ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1183ba95c745SQuentin Monnet { 1184ba95c745SQuentin Monnet size_t i, j; 1185ba95c745SQuentin Monnet char c; 1186ba95c745SQuentin Monnet 1187ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1188ba95c745SQuentin Monnet /* Row offset */ 1189ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1190ba95c745SQuentin Monnet 1191ba95c745SQuentin Monnet /* Hexadecimal values */ 1192ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1193ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1194ba95c745SQuentin Monnet j % 2 ? " " : ""); 1195ba95c745SQuentin Monnet for (; j < i + 16; j++) 1196ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1197ba95c745SQuentin Monnet 1198ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1199ba95c745SQuentin Monnet fprintf(f, "| "); 1200ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1201ba95c745SQuentin Monnet c = *(char *)(data + j); 1202ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1203ba95c745SQuentin Monnet c = '.'; 1204ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1205ba95c745SQuentin Monnet } 1206ba95c745SQuentin Monnet 1207ba95c745SQuentin Monnet fprintf(f, "\n"); 1208ba95c745SQuentin Monnet } 1209ba95c745SQuentin Monnet } 1210ba95c745SQuentin Monnet 1211ba95c745SQuentin Monnet static int 1212ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1213ba95c745SQuentin Monnet const char *json_key) 1214ba95c745SQuentin Monnet { 1215ba95c745SQuentin Monnet size_t nb_written; 1216ba95c745SQuentin Monnet FILE *f; 1217ba95c745SQuentin Monnet 1218ba95c745SQuentin Monnet if (!fname) 1219ba95c745SQuentin Monnet return 0; 1220ba95c745SQuentin Monnet 1221ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1222ba95c745SQuentin Monnet f = stdout; 1223ba95c745SQuentin Monnet if (json_output) { 1224ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1225ba95c745SQuentin Monnet print_data_json(data, size); 1226ba95c745SQuentin Monnet } else { 1227ba95c745SQuentin Monnet hex_print(data, size, f); 1228ba95c745SQuentin Monnet } 1229ba95c745SQuentin Monnet return 0; 1230ba95c745SQuentin Monnet } 1231ba95c745SQuentin Monnet 1232ba95c745SQuentin Monnet f = fopen(fname, "w"); 1233ba95c745SQuentin Monnet if (!f) { 1234ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1235ba95c745SQuentin Monnet return -1; 1236ba95c745SQuentin Monnet } 1237ba95c745SQuentin Monnet 1238ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1239ba95c745SQuentin Monnet fclose(f); 1240ba95c745SQuentin Monnet if (nb_written != size) { 1241ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1242ba95c745SQuentin Monnet return -1; 1243ba95c745SQuentin Monnet } 1244ba95c745SQuentin Monnet 1245ba95c745SQuentin Monnet return 0; 1246ba95c745SQuentin Monnet } 1247ba95c745SQuentin Monnet 1248ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1249ba95c745SQuentin Monnet { 1250ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1251ba95c745SQuentin Monnet if (!*data_ptr) { 1252ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1253ba95c745SQuentin Monnet strerror(errno)); 1254ba95c745SQuentin Monnet return -1; 1255ba95c745SQuentin Monnet } 1256ba95c745SQuentin Monnet 1257ba95c745SQuentin Monnet return 0; 1258ba95c745SQuentin Monnet } 1259ba95c745SQuentin Monnet 1260ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1261ba95c745SQuentin Monnet { 1262ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1263ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1264ba95c745SQuentin Monnet struct bpf_prog_test_run_attr test_attr = {0}; 1265ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1266ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1267ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1268ba95c745SQuentin Monnet unsigned int repeat = 1; 1269ba95c745SQuentin Monnet int fd, err; 1270ba95c745SQuentin Monnet 1271ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1272ba95c745SQuentin Monnet return -1; 1273ba95c745SQuentin Monnet 1274ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1275ba95c745SQuentin Monnet if (fd < 0) 1276ba95c745SQuentin Monnet return -1; 1277ba95c745SQuentin Monnet 1278ba95c745SQuentin Monnet while (argc) { 1279ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1280ba95c745SQuentin Monnet "data_size_out", NULL)) 1281ba95c745SQuentin Monnet return -1; 1282ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1283ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1284ba95c745SQuentin Monnet return -1; 1285ba95c745SQuentin Monnet 1286ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1287ba95c745SQuentin Monnet NEXT_ARG(); 1288ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1289ba95c745SQuentin Monnet return -1; 1290ba95c745SQuentin Monnet 1291ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1292ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1293ba95c745SQuentin Monnet return -1; 1294ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1295ba95c745SQuentin Monnet NEXT_ARG(); 1296ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1297ba95c745SQuentin Monnet return -1; 1298ba95c745SQuentin Monnet 1299ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1300ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1301ba95c745SQuentin Monnet char *endptr; 1302ba95c745SQuentin Monnet 1303ba95c745SQuentin Monnet NEXT_ARG(); 1304ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1305ba95c745SQuentin Monnet return -1; 1306ba95c745SQuentin Monnet 1307ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1308ba95c745SQuentin Monnet if (*endptr) { 1309ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1310ba95c745SQuentin Monnet *argv); 1311ba95c745SQuentin Monnet return -1; 1312ba95c745SQuentin Monnet } 1313ba95c745SQuentin Monnet NEXT_ARG(); 1314ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1315ba95c745SQuentin Monnet NEXT_ARG(); 1316ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1317ba95c745SQuentin Monnet return -1; 1318ba95c745SQuentin Monnet 1319ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1320ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1321ba95c745SQuentin Monnet return -1; 1322ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1323ba95c745SQuentin Monnet NEXT_ARG(); 1324ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1325ba95c745SQuentin Monnet return -1; 1326ba95c745SQuentin Monnet 1327ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1328ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1329ba95c745SQuentin Monnet char *endptr; 1330ba95c745SQuentin Monnet 1331ba95c745SQuentin Monnet NEXT_ARG(); 1332ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1333ba95c745SQuentin Monnet return -1; 1334ba95c745SQuentin Monnet 1335ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1336ba95c745SQuentin Monnet if (*endptr) { 1337ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1338ba95c745SQuentin Monnet *argv); 1339ba95c745SQuentin Monnet return -1; 1340ba95c745SQuentin Monnet } 1341ba95c745SQuentin Monnet NEXT_ARG(); 1342ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1343ba95c745SQuentin Monnet char *endptr; 1344ba95c745SQuentin Monnet 1345ba95c745SQuentin Monnet NEXT_ARG(); 1346ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1347ba95c745SQuentin Monnet return -1; 1348ba95c745SQuentin Monnet 1349ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1350ba95c745SQuentin Monnet if (*endptr) { 1351ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1352ba95c745SQuentin Monnet *argv); 1353ba95c745SQuentin Monnet return -1; 1354ba95c745SQuentin Monnet } 1355ba95c745SQuentin Monnet NEXT_ARG(); 1356ba95c745SQuentin Monnet } else { 1357ba95c745SQuentin 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'?", 1358ba95c745SQuentin Monnet *argv); 1359ba95c745SQuentin Monnet return -1; 1360ba95c745SQuentin Monnet } 1361ba95c745SQuentin Monnet } 1362ba95c745SQuentin Monnet 1363ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1364ba95c745SQuentin Monnet if (err) 1365ba95c745SQuentin Monnet return -1; 1366ba95c745SQuentin Monnet 1367ba95c745SQuentin Monnet if (data_in) { 1368ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1369ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1370ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1371ba95c745SQuentin Monnet if (err) 1372ba95c745SQuentin Monnet goto free_data_in; 1373ba95c745SQuentin Monnet } 1374ba95c745SQuentin Monnet 1375ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1376ba95c745SQuentin Monnet if (err) 1377ba95c745SQuentin Monnet goto free_data_out; 1378ba95c745SQuentin Monnet 1379ba95c745SQuentin Monnet if (ctx_in) { 1380ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1381ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1382ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1383ba95c745SQuentin Monnet if (err) 1384ba95c745SQuentin Monnet goto free_ctx_in; 1385ba95c745SQuentin Monnet } 1386ba95c745SQuentin Monnet 1387ba95c745SQuentin Monnet test_attr.prog_fd = fd; 1388ba95c745SQuentin Monnet test_attr.repeat = repeat; 1389ba95c745SQuentin Monnet test_attr.data_in = data_in; 1390ba95c745SQuentin Monnet test_attr.data_out = data_out; 1391ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1392ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1393ba95c745SQuentin Monnet 1394ba95c745SQuentin Monnet err = bpf_prog_test_run_xattr(&test_attr); 1395ba95c745SQuentin Monnet if (err) { 1396ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1397ba95c745SQuentin Monnet goto free_ctx_out; 1398ba95c745SQuentin Monnet } 1399ba95c745SQuentin Monnet 1400ba95c745SQuentin Monnet err = 0; 1401ba95c745SQuentin Monnet 1402ba95c745SQuentin Monnet if (json_output) 1403ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1404ba95c745SQuentin Monnet 1405ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1406ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1407ba95c745SQuentin Monnet */ 1408ba95c745SQuentin Monnet if (test_attr.data_size_out) 1409ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1410ba95c745SQuentin Monnet test_attr.data_size_out, 1411ba95c745SQuentin Monnet data_fname_out, "data_out"); 1412ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1413ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1414ba95c745SQuentin Monnet test_attr.ctx_size_out, 1415ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1416ba95c745SQuentin Monnet 1417ba95c745SQuentin Monnet if (json_output) { 1418ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1419ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1420ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1421ba95c745SQuentin Monnet } else { 1422ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1423ba95c745SQuentin Monnet test_attr.retval, 1424ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1425ba95c745SQuentin Monnet } 1426ba95c745SQuentin Monnet 1427ba95c745SQuentin Monnet free_ctx_out: 1428ba95c745SQuentin Monnet free(ctx_out); 1429ba95c745SQuentin Monnet free_ctx_in: 1430ba95c745SQuentin Monnet free(ctx_in); 1431ba95c745SQuentin Monnet free_data_out: 1432ba95c745SQuentin Monnet free(data_out); 1433ba95c745SQuentin Monnet free_data_in: 1434ba95c745SQuentin Monnet free(data_in); 1435ba95c745SQuentin Monnet 1436ba95c745SQuentin Monnet return err; 1437ba95c745SQuentin Monnet } 1438ba95c745SQuentin Monnet 14396ae32b29SQuentin Monnet static int 14406ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14416ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14426ae32b29SQuentin Monnet { 14436ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14446ae32b29SQuentin Monnet int ret; 14456ae32b29SQuentin Monnet 14466ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14476ae32b29SQuentin Monnet if (!ret) 14486ae32b29SQuentin Monnet return ret; 14496ae32b29SQuentin Monnet 14506ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14516ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14526ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14536ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14546ae32b29SQuentin Monnet 14556ae32b29SQuentin Monnet return ret; 14566ae32b29SQuentin Monnet } 14576ae32b29SQuentin Monnet 145877380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 145949a086c2SRoman Gushchin { 146032e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1461e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1462e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1463e00aca65SAndrii Nakryiko ); 1464e00aca65SAndrii Nakryiko struct bpf_object_load_attr load_attr = { 0 }; 146555d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 14663ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 146777380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 14683ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 14693767a94bSStanislav Fomichev const char *pinmaps = NULL; 147049a086c2SRoman Gushchin struct bpf_object *obj; 1471c8406848SJakub Kicinski struct bpf_map *map; 1472c8406848SJakub Kicinski const char *pinfile; 14733ff5a4dcSJakub Kicinski unsigned int i, j; 1474c8406848SJakub Kicinski __u32 ifindex = 0; 147532e3e58eSAndrii Nakryiko const char *file; 14763ff5a4dcSJakub Kicinski int idx, err; 147749a086c2SRoman Gushchin 147832e3e58eSAndrii Nakryiko 14798d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 14808d1fc3deSJakub Kicinski return -1; 148132e3e58eSAndrii Nakryiko file = GET_ARG(); 14828d1fc3deSJakub Kicinski pinfile = GET_ARG(); 148349a086c2SRoman Gushchin 1484ba6dd679SJakub Kicinski while (argc) { 148549f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 148649f2cba3SJakub Kicinski char *type; 148749f2cba3SJakub Kicinski 148849f2cba3SJakub Kicinski NEXT_ARG(); 148949f2cba3SJakub Kicinski 149032e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 149149f2cba3SJakub Kicinski p_err("program type already specified"); 14923ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 149349f2cba3SJakub Kicinski } 149449f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 14953ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 149649f2cba3SJakub Kicinski 149749f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 149849f2cba3SJakub Kicinski type = malloc(strlen(*argv) + 2); 149949f2cba3SJakub Kicinski if (!type) { 150049f2cba3SJakub Kicinski p_err("mem alloc failed"); 15013ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 150249f2cba3SJakub Kicinski } 150349f2cba3SJakub Kicinski *type = 0; 150449f2cba3SJakub Kicinski strcat(type, *argv); 150549f2cba3SJakub Kicinski strcat(type, "/"); 150649f2cba3SJakub Kicinski 15076ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1508c8406848SJakub Kicinski &expected_attach_type); 150949f2cba3SJakub Kicinski free(type); 1510c76e4c22STaeung Song if (err < 0) 15113ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 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 1549dde7011aSJakub Kicinski new_map_replace = 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 1593ac4e0e05SYonghong Song set_max_rlimit(); 1594ac4e0e05SYonghong Song 159532e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1596d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1597c8406848SJakub Kicinski p_err("failed to open object file"); 15983ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 159949a086c2SRoman Gushchin } 160049a086c2SRoman Gushchin 160177380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 160232e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1603c8406848SJakub Kicinski 160432e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1605fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1606c8406848SJakub Kicinski 16076ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1608c8406848SJakub Kicinski &expected_attach_type); 1609c76e4c22STaeung Song if (err < 0) 1610c8406848SJakub Kicinski goto err_close_obj; 1611c8406848SJakub Kicinski } 161277380998SStanislav Fomichev 161377380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 161477380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 161577380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 161677380998SStanislav Fomichev } 1617c8406848SJakub Kicinski 16183ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16193ff5a4dcSJakub Kicinski map_replace_compar); 16203ff5a4dcSJakub Kicinski 16213ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 16223ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 16233ff5a4dcSJakub Kicinski */ 16243ff5a4dcSJakub Kicinski j = 0; 16253ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 16263ff5a4dcSJakub Kicinski i = 0; 1627f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16283ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 16293ff5a4dcSJakub Kicinski map_replace[j].idx = i; 16303ff5a4dcSJakub Kicinski break; 16313ff5a4dcSJakub Kicinski } 16323ff5a4dcSJakub Kicinski i++; 16333ff5a4dcSJakub Kicinski } 16343ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 16353ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 16363ff5a4dcSJakub Kicinski goto err_close_obj; 16373ff5a4dcSJakub Kicinski } 16383ff5a4dcSJakub Kicinski j++; 16393ff5a4dcSJakub Kicinski } 16403ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 16413ff5a4dcSJakub Kicinski if (j) 16423ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16433ff5a4dcSJakub Kicinski map_replace_compar); 16443ff5a4dcSJakub Kicinski 16453ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 16463ff5a4dcSJakub Kicinski j = 0; 16473ff5a4dcSJakub Kicinski idx = 0; 1648f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 1649c8406848SJakub Kicinski if (!bpf_map__is_offload_neutral(map)) 1650c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1651c8406848SJakub Kicinski 16523ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 16533ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 16543ff5a4dcSJakub Kicinski if (err) { 16553ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 16563ff5a4dcSJakub Kicinski goto err_close_obj; 16573ff5a4dcSJakub Kicinski } 16583ff5a4dcSJakub Kicinski 16593ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 16603ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 16613ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 16623ff5a4dcSJakub Kicinski idx); 16633ff5a4dcSJakub Kicinski goto err_close_obj; 16643ff5a4dcSJakub Kicinski } 16653ff5a4dcSJakub Kicinski } 16663ff5a4dcSJakub Kicinski 16673ff5a4dcSJakub Kicinski idx++; 16683ff5a4dcSJakub Kicinski } 16693ff5a4dcSJakub Kicinski if (j < old_map_fds) { 16703ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 16713ff5a4dcSJakub Kicinski goto err_close_obj; 16723ff5a4dcSJakub Kicinski } 16733ff5a4dcSJakub Kicinski 167455d77807SQuentin Monnet load_attr.obj = obj; 167555d77807SQuentin Monnet if (verifier_logs) 167655d77807SQuentin Monnet /* log_level1 + log_level2 + stats, but not stable UAPI */ 167755d77807SQuentin Monnet load_attr.log_level = 1 + 2 + 4; 167855d77807SQuentin Monnet 167955d77807SQuentin Monnet err = bpf_object__load_xattr(&load_attr); 1680c8406848SJakub Kicinski if (err) { 1681c8406848SJakub Kicinski p_err("failed to load object file"); 1682c8406848SJakub Kicinski goto err_close_obj; 1683c8406848SJakub Kicinski } 1684c8406848SJakub Kicinski 168577380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 168677380998SStanislav Fomichev if (err) 1687bfee71fbSJakub Kicinski goto err_close_obj; 168849a086c2SRoman Gushchin 168977380998SStanislav Fomichev if (first_prog_only) { 16906f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 169177380998SStanislav Fomichev if (!prog) { 169277380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 169377380998SStanislav Fomichev goto err_close_obj; 169477380998SStanislav Fomichev } 169577380998SStanislav Fomichev 169677380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 169777380998SStanislav Fomichev if (err) { 169877380998SStanislav Fomichev p_err("failed to pin program %s", 1699fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 170077380998SStanislav Fomichev goto err_close_obj; 170177380998SStanislav Fomichev } 170277380998SStanislav Fomichev } else { 170377380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 170477380998SStanislav Fomichev if (err) { 170577380998SStanislav Fomichev p_err("failed to pin all programs"); 170677380998SStanislav Fomichev goto err_close_obj; 170777380998SStanislav Fomichev } 170877380998SStanislav Fomichev } 170977380998SStanislav Fomichev 17103767a94bSStanislav Fomichev if (pinmaps) { 17113767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 17123767a94bSStanislav Fomichev if (err) { 17133767a94bSStanislav Fomichev p_err("failed to pin all maps"); 17143767a94bSStanislav Fomichev goto err_unpin; 17153767a94bSStanislav Fomichev } 17163767a94bSStanislav Fomichev } 17173767a94bSStanislav Fomichev 171849a086c2SRoman Gushchin if (json_output) 171949a086c2SRoman Gushchin jsonw_null(json_wtr); 172049a086c2SRoman Gushchin 1721bfee71fbSJakub Kicinski bpf_object__close(obj); 17223ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17233ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17243ff5a4dcSJakub Kicinski free(map_replace); 1725bfee71fbSJakub Kicinski 172649a086c2SRoman Gushchin return 0; 1727bfee71fbSJakub Kicinski 17283767a94bSStanislav Fomichev err_unpin: 17293767a94bSStanislav Fomichev if (first_prog_only) 17303767a94bSStanislav Fomichev unlink(pinfile); 17313767a94bSStanislav Fomichev else 17323767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1733bfee71fbSJakub Kicinski err_close_obj: 1734bfee71fbSJakub Kicinski bpf_object__close(obj); 17353ff5a4dcSJakub Kicinski err_free_reuse_maps: 17363ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17373ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17383ff5a4dcSJakub Kicinski free(map_replace); 1739bfee71fbSJakub Kicinski return -1; 174049a086c2SRoman Gushchin } 174149a086c2SRoman Gushchin 1742d510296dSAlexei Starovoitov static int count_open_fds(void) 1743d510296dSAlexei Starovoitov { 1744d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1745d510296dSAlexei Starovoitov struct dirent *de; 1746d510296dSAlexei Starovoitov int cnt = -3; 1747d510296dSAlexei Starovoitov 1748d510296dSAlexei Starovoitov if (!dp) 1749d510296dSAlexei Starovoitov return -1; 1750d510296dSAlexei Starovoitov 1751d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1752d510296dSAlexei Starovoitov cnt++; 1753d510296dSAlexei Starovoitov 1754d510296dSAlexei Starovoitov closedir(dp); 1755d510296dSAlexei Starovoitov return cnt; 1756d510296dSAlexei Starovoitov } 1757d510296dSAlexei Starovoitov 1758d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1759d510296dSAlexei Starovoitov { 1760d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1761d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1762d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1763d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1764d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1765d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1766d510296dSAlexei Starovoitov char *log_buf; 1767d510296dSAlexei Starovoitov 1768d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1769d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1770d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1771d510296dSAlexei Starovoitov ctx->log_level = 1; 1772d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1773d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1774d510296dSAlexei Starovoitov if (!log_buf) 1775d510296dSAlexei Starovoitov return -ENOMEM; 1776d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1777d510296dSAlexei Starovoitov opts.ctx = ctx; 1778d510296dSAlexei Starovoitov opts.data = gen->data; 1779d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1780d510296dSAlexei Starovoitov opts.insns = gen->insns; 1781d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1782d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1783d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1784d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1785d510296dSAlexei Starovoitov if (err < 0) { 1786d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1787d510296dSAlexei Starovoitov if (fd_delta) 1788d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1789d510296dSAlexei Starovoitov fd_delta); 1790d510296dSAlexei Starovoitov } 1791d510296dSAlexei Starovoitov free(log_buf); 1792d510296dSAlexei Starovoitov return err; 1793d510296dSAlexei Starovoitov } 1794d510296dSAlexei Starovoitov 1795d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1796d510296dSAlexei Starovoitov { 1797d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1798d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1799d510296dSAlexei Starovoitov struct bpf_object_load_attr load_attr = {}; 1800d510296dSAlexei Starovoitov struct bpf_object *obj; 1801d510296dSAlexei Starovoitov const char *file; 1802d510296dSAlexei Starovoitov int err = 0; 1803d510296dSAlexei Starovoitov 1804d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1805d510296dSAlexei Starovoitov return -1; 1806d510296dSAlexei Starovoitov file = GET_ARG(); 1807d510296dSAlexei Starovoitov 1808d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1809d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1810d510296dSAlexei Starovoitov p_err("failed to open object file"); 1811d510296dSAlexei Starovoitov goto err_close_obj; 1812d510296dSAlexei Starovoitov } 1813d510296dSAlexei Starovoitov 1814d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1815d510296dSAlexei Starovoitov if (err) 1816d510296dSAlexei Starovoitov goto err_close_obj; 1817d510296dSAlexei Starovoitov 1818d510296dSAlexei Starovoitov load_attr.obj = obj; 1819d510296dSAlexei Starovoitov if (verifier_logs) 1820d510296dSAlexei Starovoitov /* log_level1 + log_level2 + stats, but not stable UAPI */ 1821d510296dSAlexei Starovoitov load_attr.log_level = 1 + 2 + 4; 1822d510296dSAlexei Starovoitov 1823d510296dSAlexei Starovoitov err = bpf_object__load_xattr(&load_attr); 1824d510296dSAlexei Starovoitov if (err) { 1825d510296dSAlexei Starovoitov p_err("failed to load object file"); 1826d510296dSAlexei Starovoitov goto err_close_obj; 1827d510296dSAlexei Starovoitov } 1828d510296dSAlexei Starovoitov 1829d510296dSAlexei Starovoitov if (verifier_logs) { 1830d510296dSAlexei Starovoitov struct dump_data dd = {}; 1831d510296dSAlexei Starovoitov 1832d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1833d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1834d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1835d510296dSAlexei Starovoitov } 1836d510296dSAlexei Starovoitov err = try_loader(&gen); 1837d510296dSAlexei Starovoitov err_close_obj: 1838d510296dSAlexei Starovoitov bpf_object__close(obj); 1839d510296dSAlexei Starovoitov return err; 1840d510296dSAlexei Starovoitov } 1841d510296dSAlexei Starovoitov 184277380998SStanislav Fomichev static int do_load(int argc, char **argv) 184377380998SStanislav Fomichev { 1844d510296dSAlexei Starovoitov if (use_loader) 1845d510296dSAlexei Starovoitov return do_loader(argc, argv); 184677380998SStanislav Fomichev return load_with_options(argc, argv, true); 184777380998SStanislav Fomichev } 184877380998SStanislav Fomichev 184977380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 185077380998SStanislav Fomichev { 185177380998SStanislav Fomichev return load_with_options(argc, argv, false); 185277380998SStanislav Fomichev } 185377380998SStanislav Fomichev 185447c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 185547c09d6aSSong Liu 185647c09d6aSSong Liu static int do_profile(int argc, char **argv) 185747c09d6aSSong Liu { 185814e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 185947c09d6aSSong Liu return 0; 186047c09d6aSSong Liu } 186147c09d6aSSong Liu 186247c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 186347c09d6aSSong Liu 186447c09d6aSSong Liu #include "profiler.skel.h" 186547c09d6aSSong Liu 186647c09d6aSSong Liu struct profile_metric { 186747c09d6aSSong Liu const char *name; 186847c09d6aSSong Liu struct bpf_perf_event_value val; 186947c09d6aSSong Liu struct perf_event_attr attr; 187047c09d6aSSong Liu bool selected; 187147c09d6aSSong Liu 187247c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 187347c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 187447c09d6aSSong Liu const char *ratio_desc; 187547c09d6aSSong Liu const float ratio_mul; 187647c09d6aSSong Liu } metrics[] = { 187747c09d6aSSong Liu { 187847c09d6aSSong Liu .name = "cycles", 187947c09d6aSSong Liu .attr = { 188047c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 188147c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 188247c09d6aSSong Liu .exclude_user = 1, 188347c09d6aSSong Liu }, 188447c09d6aSSong Liu }, 188547c09d6aSSong Liu { 188647c09d6aSSong Liu .name = "instructions", 188747c09d6aSSong Liu .attr = { 188847c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 188947c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 189047c09d6aSSong Liu .exclude_user = 1, 189147c09d6aSSong Liu }, 189247c09d6aSSong Liu .ratio_metric = 1, 189347c09d6aSSong Liu .ratio_desc = "insns per cycle", 189447c09d6aSSong Liu .ratio_mul = 1.0, 189547c09d6aSSong Liu }, 189647c09d6aSSong Liu { 189747c09d6aSSong Liu .name = "l1d_loads", 189847c09d6aSSong Liu .attr = { 189947c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 190047c09d6aSSong Liu .config = 190147c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 190247c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 190347c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 190447c09d6aSSong Liu .exclude_user = 1, 190547c09d6aSSong Liu }, 190647c09d6aSSong Liu }, 190747c09d6aSSong Liu { 190847c09d6aSSong Liu .name = "llc_misses", 190947c09d6aSSong Liu .attr = { 191047c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 191147c09d6aSSong Liu .config = 191247c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 191347c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 191447c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 191547c09d6aSSong Liu .exclude_user = 1 191647c09d6aSSong Liu }, 191747c09d6aSSong Liu .ratio_metric = 2, 191847c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 191947c09d6aSSong Liu .ratio_mul = 1e6, 192047c09d6aSSong Liu }, 1921450d060eSYonghong Song { 1922450d060eSYonghong Song .name = "itlb_misses", 1923450d060eSYonghong Song .attr = { 1924450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1925450d060eSYonghong Song .config = 1926450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 1927450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1928450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1929450d060eSYonghong Song .exclude_user = 1 1930450d060eSYonghong Song }, 1931450d060eSYonghong Song .ratio_metric = 2, 1932450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 1933450d060eSYonghong Song .ratio_mul = 1e6, 1934450d060eSYonghong Song }, 1935450d060eSYonghong Song { 1936450d060eSYonghong Song .name = "dtlb_misses", 1937450d060eSYonghong Song .attr = { 1938450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1939450d060eSYonghong Song .config = 1940450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 1941450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1942450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1943450d060eSYonghong Song .exclude_user = 1 1944450d060eSYonghong Song }, 1945450d060eSYonghong Song .ratio_metric = 2, 1946450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 1947450d060eSYonghong Song .ratio_mul = 1e6, 1948450d060eSYonghong Song }, 194947c09d6aSSong Liu }; 195047c09d6aSSong Liu 195147c09d6aSSong Liu static __u64 profile_total_count; 195247c09d6aSSong Liu 195347c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 195447c09d6aSSong Liu 195547c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 195647c09d6aSSong Liu { 195747c09d6aSSong Liu unsigned int metric_cnt; 195847c09d6aSSong Liu int selected_cnt = 0; 195947c09d6aSSong Liu unsigned int i; 196047c09d6aSSong Liu 196147c09d6aSSong Liu metric_cnt = sizeof(metrics) / sizeof(struct profile_metric); 196247c09d6aSSong Liu 196347c09d6aSSong Liu while (argc > 0) { 196447c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 196547c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 196647c09d6aSSong Liu if (!metrics[i].selected) 196747c09d6aSSong Liu selected_cnt++; 196847c09d6aSSong Liu metrics[i].selected = true; 196947c09d6aSSong Liu break; 197047c09d6aSSong Liu } 197147c09d6aSSong Liu } 197247c09d6aSSong Liu if (i == metric_cnt) { 197347c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 197447c09d6aSSong Liu return -1; 197547c09d6aSSong Liu } 197647c09d6aSSong Liu NEXT_ARG(); 197747c09d6aSSong Liu } 197847c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 197947c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 198047c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 198147c09d6aSSong Liu return -1; 198247c09d6aSSong Liu } 198347c09d6aSSong Liu return selected_cnt; 198447c09d6aSSong Liu } 198547c09d6aSSong Liu 198647c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 198747c09d6aSSong Liu { 198847c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 198947c09d6aSSong Liu int reading_map_fd, count_map_fd; 199047c09d6aSSong Liu __u64 counts[num_cpu]; 199147c09d6aSSong Liu __u32 key = 0; 199247c09d6aSSong Liu int err; 199347c09d6aSSong Liu 199447c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 199547c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 199647c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 199747c09d6aSSong Liu p_err("failed to get fd for map"); 199847c09d6aSSong Liu return; 199947c09d6aSSong Liu } 200047c09d6aSSong Liu 200147c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 200247c09d6aSSong Liu if (err) { 200347c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 200447c09d6aSSong Liu return; 200547c09d6aSSong Liu } 200647c09d6aSSong Liu 200747c09d6aSSong Liu profile_total_count = 0; 200847c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 200947c09d6aSSong Liu profile_total_count += counts[cpu]; 201047c09d6aSSong Liu 201147c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 201247c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 201347c09d6aSSong Liu 201447c09d6aSSong Liu if (!metrics[m].selected) 201547c09d6aSSong Liu continue; 201647c09d6aSSong Liu 201747c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 201847c09d6aSSong Liu if (err) { 201947c09d6aSSong Liu p_err("failed to read reading_map: %s", 202047c09d6aSSong Liu strerror(errno)); 202147c09d6aSSong Liu return; 202247c09d6aSSong Liu } 202347c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 202447c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 202547c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 202647c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 202747c09d6aSSong Liu } 202847c09d6aSSong Liu key++; 202947c09d6aSSong Liu } 203047c09d6aSSong Liu } 203147c09d6aSSong Liu 203247c09d6aSSong Liu static void profile_print_readings_json(void) 203347c09d6aSSong Liu { 203447c09d6aSSong Liu __u32 m; 203547c09d6aSSong Liu 203647c09d6aSSong Liu jsonw_start_array(json_wtr); 203747c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 203847c09d6aSSong Liu if (!metrics[m].selected) 203947c09d6aSSong Liu continue; 204047c09d6aSSong Liu jsonw_start_object(json_wtr); 204147c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 204247c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 204347c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 204447c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 204547c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 204647c09d6aSSong Liu 204747c09d6aSSong Liu jsonw_end_object(json_wtr); 204847c09d6aSSong Liu } 204947c09d6aSSong Liu jsonw_end_array(json_wtr); 205047c09d6aSSong Liu } 205147c09d6aSSong Liu 205247c09d6aSSong Liu static void profile_print_readings_plain(void) 205347c09d6aSSong Liu { 205447c09d6aSSong Liu __u32 m; 205547c09d6aSSong Liu 205647c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 205747c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 205847c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 205947c09d6aSSong Liu int r; 206047c09d6aSSong Liu 206147c09d6aSSong Liu if (!metrics[m].selected) 206247c09d6aSSong Liu continue; 206347c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 206447c09d6aSSong Liu 206547c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 206647c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 206747c09d6aSSong Liu metrics[r].val.counter > 0) { 206847c09d6aSSong Liu printf("# %8.2f %-30s", 206947c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 207047c09d6aSSong Liu metrics[r].val.counter, 207147c09d6aSSong Liu metrics[m].ratio_desc); 207247c09d6aSSong Liu } else { 207347c09d6aSSong Liu printf("%-41s", ""); 207447c09d6aSSong Liu } 207547c09d6aSSong Liu 207647c09d6aSSong Liu if (val->enabled > val->running) 207747c09d6aSSong Liu printf("(%4.2f%%)", 207847c09d6aSSong Liu val->running * 100.0 / val->enabled); 207947c09d6aSSong Liu printf("\n"); 208047c09d6aSSong Liu } 208147c09d6aSSong Liu } 208247c09d6aSSong Liu 208347c09d6aSSong Liu static void profile_print_readings(void) 208447c09d6aSSong Liu { 208547c09d6aSSong Liu if (json_output) 208647c09d6aSSong Liu profile_print_readings_json(); 208747c09d6aSSong Liu else 208847c09d6aSSong Liu profile_print_readings_plain(); 208947c09d6aSSong Liu } 209047c09d6aSSong Liu 209147c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 209247c09d6aSSong Liu { 2093*c59765cfSDave Marchevsky struct bpf_func_info func_info; 2094*c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2095*c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 209647c09d6aSSong Liu const struct btf_type *t; 2097*c59765cfSDave Marchevsky __u32 func_info_rec_size; 2098369e955bSQuentin Monnet struct btf *btf = NULL; 209947c09d6aSSong Liu char *name = NULL; 2100*c59765cfSDave Marchevsky int err; 210147c09d6aSSong Liu 2102*c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2103*c59765cfSDave Marchevsky if (err) { 2104*c59765cfSDave Marchevsky p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd); 2105*c59765cfSDave Marchevsky goto out; 210647c09d6aSSong Liu } 210747c09d6aSSong Liu 2108*c59765cfSDave Marchevsky if (info.btf_id == 0) { 210947c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 211047c09d6aSSong Liu goto out; 211147c09d6aSSong Liu } 211247c09d6aSSong Liu 2113*c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2114*c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 2115*c59765cfSDave Marchevsky p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd); 2116*c59765cfSDave Marchevsky goto out; 2117*c59765cfSDave Marchevsky } 2118*c59765cfSDave Marchevsky 2119*c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2120*c59765cfSDave Marchevsky info.nr_func_info = 1; 2121*c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2122*c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2123*c59765cfSDave Marchevsky 2124*c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2125*c59765cfSDave Marchevsky if (err) { 2126*c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2127*c59765cfSDave Marchevsky goto out; 2128*c59765cfSDave Marchevsky } 2129*c59765cfSDave Marchevsky 2130*c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 213186f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 213286f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 213386f4b7f2SQuentin Monnet goto out; 213486f4b7f2SQuentin Monnet } 213586f4b7f2SQuentin Monnet 2136*c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 213747c09d6aSSong Liu if (!t) { 213847c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2139*c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 214047c09d6aSSong Liu goto out; 214147c09d6aSSong Liu } 214247c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 214347c09d6aSSong Liu out: 2144369e955bSQuentin Monnet btf__free(btf); 214547c09d6aSSong Liu return name; 214647c09d6aSSong Liu } 214747c09d6aSSong Liu 214847c09d6aSSong Liu static struct profiler_bpf *profile_obj; 214947c09d6aSSong Liu static int profile_tgt_fd = -1; 215047c09d6aSSong Liu static char *profile_tgt_name; 215147c09d6aSSong Liu static int *profile_perf_events; 215247c09d6aSSong Liu static int profile_perf_event_cnt; 215347c09d6aSSong Liu 215447c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 215547c09d6aSSong Liu { 215647c09d6aSSong Liu int i; 215747c09d6aSSong Liu 215847c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 215947c09d6aSSong Liu close(profile_perf_events[i]); 216047c09d6aSSong Liu 216147c09d6aSSong Liu free(profile_perf_events); 216247c09d6aSSong Liu profile_perf_event_cnt = 0; 216347c09d6aSSong Liu } 216447c09d6aSSong Liu 216547c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 216647c09d6aSSong Liu { 216747c09d6aSSong Liu unsigned int cpu, m; 216847c09d6aSSong Liu int map_fd, pmu_fd; 216947c09d6aSSong Liu 217047c09d6aSSong Liu profile_perf_events = calloc( 217147c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 217247c09d6aSSong Liu if (!profile_perf_events) { 217347c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 217447c09d6aSSong Liu strerror(errno)); 217547c09d6aSSong Liu return -1; 217647c09d6aSSong Liu } 217747c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 217847c09d6aSSong Liu if (map_fd < 0) { 217947c09d6aSSong Liu p_err("failed to get fd for events map"); 218047c09d6aSSong Liu return -1; 218147c09d6aSSong Liu } 218247c09d6aSSong Liu 218347c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 218447c09d6aSSong Liu if (!metrics[m].selected) 218547c09d6aSSong Liu continue; 218647c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 218747c09d6aSSong Liu pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 218847c09d6aSSong Liu -1/*pid*/, cpu, -1/*group_fd*/, 0); 218947c09d6aSSong Liu if (pmu_fd < 0 || 219047c09d6aSSong Liu bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 219147c09d6aSSong Liu &pmu_fd, BPF_ANY) || 219247c09d6aSSong Liu ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 219347c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 219447c09d6aSSong Liu metrics[m].name, cpu); 219547c09d6aSSong Liu return -1; 219647c09d6aSSong Liu } 219747c09d6aSSong Liu profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 219847c09d6aSSong Liu } 219947c09d6aSSong Liu } 220047c09d6aSSong Liu return 0; 220147c09d6aSSong Liu } 220247c09d6aSSong Liu 220347c09d6aSSong Liu static void profile_print_and_cleanup(void) 220447c09d6aSSong Liu { 220547c09d6aSSong Liu profile_close_perf_events(profile_obj); 220647c09d6aSSong Liu profile_read_values(profile_obj); 220747c09d6aSSong Liu profile_print_readings(); 220847c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 220947c09d6aSSong Liu 221047c09d6aSSong Liu close(profile_tgt_fd); 221147c09d6aSSong Liu free(profile_tgt_name); 221247c09d6aSSong Liu } 221347c09d6aSSong Liu 221447c09d6aSSong Liu static void int_exit(int signo) 221547c09d6aSSong Liu { 221647c09d6aSSong Liu profile_print_and_cleanup(); 221747c09d6aSSong Liu exit(0); 221847c09d6aSSong Liu } 221947c09d6aSSong Liu 222047c09d6aSSong Liu static int do_profile(int argc, char **argv) 222147c09d6aSSong Liu { 222247c09d6aSSong Liu int num_metric, num_cpu, err = -1; 222347c09d6aSSong Liu struct bpf_program *prog; 222447c09d6aSSong Liu unsigned long duration; 222547c09d6aSSong Liu char *endptr; 222647c09d6aSSong Liu 222747c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 222847c09d6aSSong Liu if (!REQ_ARGS(3)) 222947c09d6aSSong Liu return -EINVAL; 223047c09d6aSSong Liu 223147c09d6aSSong Liu /* parse target fd */ 223247c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 223347c09d6aSSong Liu if (profile_tgt_fd < 0) { 223447c09d6aSSong Liu p_err("failed to parse fd"); 223547c09d6aSSong Liu return -1; 223647c09d6aSSong Liu } 223747c09d6aSSong Liu 223847c09d6aSSong Liu /* parse profiling optional duration */ 223947c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 224047c09d6aSSong Liu NEXT_ARG(); 224147c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 224247c09d6aSSong Liu if (*endptr) 224347c09d6aSSong Liu usage(); 224447c09d6aSSong Liu NEXT_ARG(); 224547c09d6aSSong Liu } else { 224647c09d6aSSong Liu duration = UINT_MAX; 224747c09d6aSSong Liu } 224847c09d6aSSong Liu 224947c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 225047c09d6aSSong Liu if (num_metric <= 0) 225147c09d6aSSong Liu goto out; 225247c09d6aSSong Liu 225347c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 225447c09d6aSSong Liu if (num_cpu <= 0) { 225547c09d6aSSong Liu p_err("failed to identify number of CPUs"); 225647c09d6aSSong Liu goto out; 225747c09d6aSSong Liu } 225847c09d6aSSong Liu 225947c09d6aSSong Liu profile_obj = profiler_bpf__open(); 226047c09d6aSSong Liu if (!profile_obj) { 226147c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 226247c09d6aSSong Liu goto out; 226347c09d6aSSong Liu } 226447c09d6aSSong Liu 226547c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 226647c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 226747c09d6aSSong Liu 226847c09d6aSSong Liu /* adjust map sizes */ 226947c09d6aSSong Liu bpf_map__resize(profile_obj->maps.events, num_metric * num_cpu); 227047c09d6aSSong Liu bpf_map__resize(profile_obj->maps.fentry_readings, num_metric); 227147c09d6aSSong Liu bpf_map__resize(profile_obj->maps.accum_readings, num_metric); 227247c09d6aSSong Liu bpf_map__resize(profile_obj->maps.counts, 1); 227347c09d6aSSong Liu 227447c09d6aSSong Liu /* change target name */ 227547c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 227647c09d6aSSong Liu if (!profile_tgt_name) 227747c09d6aSSong Liu goto out; 227847c09d6aSSong Liu 227947c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 228047c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 228147c09d6aSSong Liu profile_tgt_name); 228247c09d6aSSong Liu if (err) { 228347c09d6aSSong Liu p_err("failed to set attach target\n"); 228447c09d6aSSong Liu goto out; 228547c09d6aSSong Liu } 228647c09d6aSSong Liu } 228747c09d6aSSong Liu 228847c09d6aSSong Liu set_max_rlimit(); 228947c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 229047c09d6aSSong Liu if (err) { 229147c09d6aSSong Liu p_err("failed to load profile_obj"); 229247c09d6aSSong Liu goto out; 229347c09d6aSSong Liu } 229447c09d6aSSong Liu 229547c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 229647c09d6aSSong Liu if (err) 229747c09d6aSSong Liu goto out; 229847c09d6aSSong Liu 229947c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 230047c09d6aSSong Liu if (err) { 230147c09d6aSSong Liu p_err("failed to attach profile_obj"); 230247c09d6aSSong Liu goto out; 230347c09d6aSSong Liu } 230447c09d6aSSong Liu signal(SIGINT, int_exit); 230547c09d6aSSong Liu 230647c09d6aSSong Liu sleep(duration); 230747c09d6aSSong Liu profile_print_and_cleanup(); 230847c09d6aSSong Liu return 0; 230947c09d6aSSong Liu 231047c09d6aSSong Liu out: 231147c09d6aSSong Liu profile_close_perf_events(profile_obj); 231247c09d6aSSong Liu if (profile_obj) 231347c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 231447c09d6aSSong Liu close(profile_tgt_fd); 231547c09d6aSSong Liu free(profile_tgt_name); 231647c09d6aSSong Liu return err; 231747c09d6aSSong Liu } 231847c09d6aSSong Liu 231947c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 232047c09d6aSSong Liu 232171bb428fSJakub Kicinski static int do_help(int argc, char **argv) 232271bb428fSJakub Kicinski { 2323004b45c0SQuentin Monnet if (json_output) { 2324004b45c0SQuentin Monnet jsonw_null(json_wtr); 2325004b45c0SQuentin Monnet return 0; 2326004b45c0SQuentin Monnet } 2327004b45c0SQuentin Monnet 232871bb428fSJakub Kicinski fprintf(stderr, 232990040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 233090040351SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 233190040351SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | opcodes | linum }]\n" 233290040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 233390040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 233477380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 23353767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 23363767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 233790040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 233890040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 233990040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2340ba95c745SQuentin Monnet " data_in FILE \\\n" 2341ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2342ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2343ba95c745SQuentin Monnet " [repeat N]\n" 234490040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 234590040351SQuentin Monnet " %1$s %2$s tracelog\n" 234690040351SQuentin Monnet " %1$s %2$s help\n" 234771bb428fSJakub Kicinski "\n" 23483ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 234971bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 235049f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 235149f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 235249f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 235349f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2354f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 235549f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 235649f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 235705ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 235805ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 235905ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2360a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 236193a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 2362b544342eSQuentin Monnet " ATTACH_TYPE := { msg_verdict | skb_verdict | stream_verdict |\n" 2363b544342eSQuentin Monnet " stream_parser | flow_dissector }\n" 2364450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2365c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 23668cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 23678cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 236871bb428fSJakub Kicinski "", 236990040351SQuentin Monnet bin_name, argv[-2]); 237071bb428fSJakub Kicinski 237171bb428fSJakub Kicinski return 0; 237271bb428fSJakub Kicinski } 237371bb428fSJakub Kicinski 237471bb428fSJakub Kicinski static const struct cmd cmds[] = { 237571bb428fSJakub Kicinski { "show", do_show }, 23766ebe6dbdSJakub Kicinski { "list", do_show }, 23779f606179SQuentin Monnet { "help", do_help }, 237871bb428fSJakub Kicinski { "dump", do_dump }, 237971bb428fSJakub Kicinski { "pin", do_pin }, 238049a086c2SRoman Gushchin { "load", do_load }, 238177380998SStanislav Fomichev { "loadall", do_loadall }, 2382b7d3826cSJohn Fastabend { "attach", do_attach }, 2383b7d3826cSJohn Fastabend { "detach", do_detach }, 238430da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2385ba95c745SQuentin Monnet { "run", do_run }, 238647c09d6aSSong Liu { "profile", do_profile }, 238771bb428fSJakub Kicinski { 0 } 238871bb428fSJakub Kicinski }; 238971bb428fSJakub Kicinski 239071bb428fSJakub Kicinski int do_prog(int argc, char **argv) 239171bb428fSJakub Kicinski { 239271bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 239371bb428fSJakub Kicinski } 2394