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 103c59765cfSDave Marchevsky static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 104c59765cfSDave Marchevsky void **info_data, size_t *const info_data_sz) 105c59765cfSDave Marchevsky { 106c59765cfSDave Marchevsky struct bpf_prog_info holder = {}; 107c59765cfSDave Marchevsky size_t needed = 0; 108c59765cfSDave Marchevsky void *ptr; 109c59765cfSDave Marchevsky 110c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 111c59765cfSDave Marchevsky holder.jited_prog_len = info->jited_prog_len; 112c59765cfSDave Marchevsky needed += info->jited_prog_len; 113c59765cfSDave Marchevsky } else { 114c59765cfSDave Marchevsky holder.xlated_prog_len = info->xlated_prog_len; 115c59765cfSDave Marchevsky needed += info->xlated_prog_len; 116c59765cfSDave Marchevsky } 117c59765cfSDave Marchevsky 118c59765cfSDave Marchevsky holder.nr_jited_ksyms = info->nr_jited_ksyms; 119c59765cfSDave Marchevsky needed += info->nr_jited_ksyms * sizeof(__u64); 120c59765cfSDave Marchevsky 121c59765cfSDave Marchevsky holder.nr_jited_func_lens = info->nr_jited_func_lens; 122c59765cfSDave Marchevsky needed += info->nr_jited_func_lens * sizeof(__u32); 123c59765cfSDave Marchevsky 124c59765cfSDave Marchevsky holder.nr_func_info = info->nr_func_info; 125c59765cfSDave Marchevsky holder.func_info_rec_size = info->func_info_rec_size; 126c59765cfSDave Marchevsky needed += info->nr_func_info * info->func_info_rec_size; 127c59765cfSDave Marchevsky 128c59765cfSDave Marchevsky holder.nr_line_info = info->nr_line_info; 129c59765cfSDave Marchevsky holder.line_info_rec_size = info->line_info_rec_size; 130c59765cfSDave Marchevsky needed += info->nr_line_info * info->line_info_rec_size; 131c59765cfSDave Marchevsky 132c59765cfSDave Marchevsky holder.nr_jited_line_info = info->nr_jited_line_info; 133c59765cfSDave Marchevsky holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 134c59765cfSDave Marchevsky needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 135c59765cfSDave Marchevsky 136c59765cfSDave Marchevsky if (needed > *info_data_sz) { 137c59765cfSDave Marchevsky ptr = realloc(*info_data, needed); 138c59765cfSDave Marchevsky if (!ptr) 139c59765cfSDave Marchevsky return -1; 140c59765cfSDave Marchevsky 141c59765cfSDave Marchevsky *info_data = ptr; 142c59765cfSDave Marchevsky *info_data_sz = needed; 143c59765cfSDave Marchevsky } 144c59765cfSDave Marchevsky ptr = *info_data; 145c59765cfSDave Marchevsky 146c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 147c59765cfSDave Marchevsky holder.jited_prog_insns = ptr_to_u64(ptr); 148c59765cfSDave Marchevsky ptr += holder.jited_prog_len; 149c59765cfSDave Marchevsky } else { 150c59765cfSDave Marchevsky holder.xlated_prog_insns = ptr_to_u64(ptr); 151c59765cfSDave Marchevsky ptr += holder.xlated_prog_len; 152c59765cfSDave Marchevsky } 153c59765cfSDave Marchevsky 154c59765cfSDave Marchevsky holder.jited_ksyms = ptr_to_u64(ptr); 155c59765cfSDave Marchevsky ptr += holder.nr_jited_ksyms * sizeof(__u64); 156c59765cfSDave Marchevsky 157c59765cfSDave Marchevsky holder.jited_func_lens = ptr_to_u64(ptr); 158c59765cfSDave Marchevsky ptr += holder.nr_jited_func_lens * sizeof(__u32); 159c59765cfSDave Marchevsky 160c59765cfSDave Marchevsky holder.func_info = ptr_to_u64(ptr); 161c59765cfSDave Marchevsky ptr += holder.nr_func_info * holder.func_info_rec_size; 162c59765cfSDave Marchevsky 163c59765cfSDave Marchevsky holder.line_info = ptr_to_u64(ptr); 164c59765cfSDave Marchevsky ptr += holder.nr_line_info * holder.line_info_rec_size; 165c59765cfSDave Marchevsky 166c59765cfSDave Marchevsky holder.jited_line_info = ptr_to_u64(ptr); 167c59765cfSDave Marchevsky ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 168c59765cfSDave Marchevsky 169c59765cfSDave Marchevsky *info = holder; 170c59765cfSDave Marchevsky return 0; 171c59765cfSDave Marchevsky } 172c59765cfSDave 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 427*b662000aSRaman Shukhau static void print_prog_header_json(struct bpf_prog_info *info, int fd) 428743cc665SQuentin Monnet { 429*b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 430*b662000aSRaman Shukhau 431743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 432743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 433743cc665SQuentin Monnet jsonw_string_field(json_wtr, "type", 434743cc665SQuentin Monnet prog_type_name[info->type]); 43571bb428fSJakub Kicinski else 436743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 43771bb428fSJakub Kicinski 438*b662000aSRaman Shukhau if (*info->name) { 439*b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 440*b662000aSRaman Shukhau jsonw_string_field(json_wtr, "name", prog_name); 441*b662000aSRaman Shukhau } 44271bb428fSJakub Kicinski 443743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 444743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 445743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 446743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 44771bb428fSJakub Kicinski 4489b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 44988ad472bSAlexei Starovoitov if (info->run_time_ns) { 45088ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 45188ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 45288ad472bSAlexei Starovoitov } 4539ed9e9baSAlexei Starovoitov if (info->recursion_misses) 4549ed9e9baSAlexei Starovoitov jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 455ec202509SPaul Chaignon } 4569b984a20SJiri Olsa 457ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 458ec202509SPaul Chaignon { 459ec202509SPaul Chaignon char *memlock; 460ec202509SPaul Chaignon 461ec202509SPaul Chaignon jsonw_start_object(json_wtr); 462*b662000aSRaman Shukhau print_prog_header_json(info, fd); 46352262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 46452262210SJakub Kicinski 465743cc665SQuentin Monnet if (info->load_time) { 46671bb428fSJakub Kicinski char buf[32]; 46771bb428fSJakub Kicinski 468743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 46971bb428fSJakub Kicinski 47071bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 471a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 472a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 473743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 47471bb428fSJakub Kicinski } 47571bb428fSJakub Kicinski 476743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 47771bb428fSJakub Kicinski 478743cc665SQuentin Monnet if (info->jited_prog_len) { 479743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 480743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 481743cc665SQuentin Monnet } else { 482743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 483743cc665SQuentin Monnet } 484743cc665SQuentin Monnet 485743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 486743cc665SQuentin Monnet if (memlock) 487743cc665SQuentin Monnet jsonw_int_field(json_wtr, "bytes_memlock", atoi(memlock)); 488743cc665SQuentin Monnet free(memlock); 489743cc665SQuentin Monnet 490743cc665SQuentin Monnet if (info->nr_map_ids) 491743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 492743cc665SQuentin Monnet 493569b0c77SPrashant Bhole if (info->btf_id) 494569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 495569b0c77SPrashant Bhole 4968f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 4978f184732SQuentin Monnet struct hashmap_entry *entry; 4984990f1f4SPrashant Bhole 4994990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 5004990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 5018f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 5028f184732SQuentin Monnet u32_as_hash_field(info->id)) 5038f184732SQuentin Monnet jsonw_string(json_wtr, entry->value); 5044990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 5054990f1f4SPrashant Bhole } 5064990f1f4SPrashant Bhole 507d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 508d53dee3fSAndrii Nakryiko 509aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 510aff52e68SYiFei Zhu 511743cc665SQuentin Monnet jsonw_end_object(json_wtr); 512743cc665SQuentin Monnet } 513743cc665SQuentin Monnet 514*b662000aSRaman Shukhau static void print_prog_header_plain(struct bpf_prog_info *info, int fd) 515743cc665SQuentin Monnet { 516*b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 517*b662000aSRaman Shukhau 518743cc665SQuentin Monnet printf("%u: ", info->id); 519743cc665SQuentin Monnet if (info->type < ARRAY_SIZE(prog_type_name)) 520743cc665SQuentin Monnet printf("%s ", prog_type_name[info->type]); 521743cc665SQuentin Monnet else 522743cc665SQuentin Monnet printf("type %u ", info->type); 523743cc665SQuentin Monnet 524*b662000aSRaman Shukhau if (*info->name) { 525*b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 526*b662000aSRaman Shukhau printf("name %s ", prog_name); 527*b662000aSRaman Shukhau } 528743cc665SQuentin Monnet 529743cc665SQuentin Monnet printf("tag "); 530743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 53152262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5329b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 53388ad472bSAlexei Starovoitov if (info->run_time_ns) 53488ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 53588ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5369ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5379ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 538743cc665SQuentin Monnet printf("\n"); 539ec202509SPaul Chaignon } 540ec202509SPaul Chaignon 541ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 542ec202509SPaul Chaignon { 543ec202509SPaul Chaignon char *memlock; 544ec202509SPaul Chaignon 545*b662000aSRaman Shukhau print_prog_header_plain(info, fd); 546743cc665SQuentin Monnet 547743cc665SQuentin Monnet if (info->load_time) { 548743cc665SQuentin Monnet char buf[32]; 549743cc665SQuentin Monnet 550743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 551743cc665SQuentin Monnet 552743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 553743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 554743cc665SQuentin Monnet } 555743cc665SQuentin Monnet 556743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 557743cc665SQuentin Monnet 558743cc665SQuentin Monnet if (info->jited_prog_len) 559743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 56071bb428fSJakub Kicinski else 56171bb428fSJakub Kicinski printf(" not jited"); 56271bb428fSJakub Kicinski 56371bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 56471bb428fSJakub Kicinski if (memlock) 56571bb428fSJakub Kicinski printf(" memlock %sB", memlock); 56671bb428fSJakub Kicinski free(memlock); 56771bb428fSJakub Kicinski 568743cc665SQuentin Monnet if (info->nr_map_ids) 569743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 57071bb428fSJakub Kicinski 5718f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5728f184732SQuentin Monnet struct hashmap_entry *entry; 5734990f1f4SPrashant Bhole 5748f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 5758f184732SQuentin Monnet u32_as_hash_field(info->id)) 5768f184732SQuentin Monnet printf("\n\tpinned %s", (char *)entry->value); 5774990f1f4SPrashant Bhole } 5784990f1f4SPrashant Bhole 579569b0c77SPrashant Bhole if (info->btf_id) 580031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 581569b0c77SPrashant Bhole 582d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 583d53dee3fSAndrii Nakryiko 58471bb428fSJakub Kicinski printf("\n"); 585aff52e68SYiFei Zhu 586aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 587743cc665SQuentin Monnet } 588743cc665SQuentin Monnet 589743cc665SQuentin Monnet static int show_prog(int fd) 590743cc665SQuentin Monnet { 591743cc665SQuentin Monnet struct bpf_prog_info info = {}; 592743cc665SQuentin Monnet __u32 len = sizeof(info); 593743cc665SQuentin Monnet int err; 594743cc665SQuentin Monnet 595743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 596743cc665SQuentin Monnet if (err) { 5979a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 598743cc665SQuentin Monnet return -1; 599743cc665SQuentin Monnet } 600743cc665SQuentin Monnet 601743cc665SQuentin Monnet if (json_output) 602743cc665SQuentin Monnet print_prog_json(&info, fd); 603743cc665SQuentin Monnet else 604743cc665SQuentin Monnet print_prog_plain(&info, fd); 60571bb428fSJakub Kicinski 60671bb428fSJakub Kicinski return 0; 60771bb428fSJakub Kicinski } 60871bb428fSJakub Kicinski 609ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 610ec202509SPaul Chaignon { 611ec202509SPaul Chaignon int *fds = NULL; 612ec202509SPaul Chaignon int nb_fds, i; 613ec202509SPaul Chaignon int err = -1; 614ec202509SPaul Chaignon 615ec202509SPaul Chaignon fds = malloc(sizeof(int)); 616ec202509SPaul Chaignon if (!fds) { 617ec202509SPaul Chaignon p_err("mem alloc failed"); 618ec202509SPaul Chaignon return -1; 619ec202509SPaul Chaignon } 620ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 621ec202509SPaul Chaignon if (nb_fds < 1) 622ec202509SPaul Chaignon goto exit_free; 623ec202509SPaul Chaignon 624ec202509SPaul Chaignon if (json_output && nb_fds > 1) 625ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 626ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 627ec202509SPaul Chaignon err = show_prog(fds[i]); 628ec202509SPaul Chaignon if (err) { 629ec202509SPaul Chaignon for (; i < nb_fds; i++) 630ec202509SPaul Chaignon close(fds[i]); 631ec202509SPaul Chaignon break; 632ec202509SPaul Chaignon } 633ec202509SPaul Chaignon close(fds[i]); 634ec202509SPaul Chaignon } 635ec202509SPaul Chaignon if (json_output && nb_fds > 1) 636ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 637ec202509SPaul Chaignon 638ec202509SPaul Chaignon exit_free: 639ec202509SPaul Chaignon free(fds); 640ec202509SPaul Chaignon return err; 641ec202509SPaul Chaignon } 642ec202509SPaul Chaignon 64371bb428fSJakub Kicinski static int do_show(int argc, char **argv) 644743cc665SQuentin Monnet { 645743cc665SQuentin Monnet __u32 id = 0; 64671bb428fSJakub Kicinski int err; 64771bb428fSJakub Kicinski int fd; 64871bb428fSJakub Kicinski 64946241271SQuentin Monnet if (show_pinned) { 6508f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6518f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 652622a5b58SMauricio Vásquez if (IS_ERR(prog_table)) { 6538f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6548f184732SQuentin Monnet return -1; 6558f184732SQuentin Monnet } 6568f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 65746241271SQuentin Monnet } 658d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6594990f1f4SPrashant Bhole 660ec202509SPaul Chaignon if (argc == 2) 661ec202509SPaul Chaignon return do_show_subset(argc, argv); 66271bb428fSJakub Kicinski 66371bb428fSJakub Kicinski if (argc) 66471bb428fSJakub Kicinski return BAD_ARG(); 66571bb428fSJakub Kicinski 666743cc665SQuentin Monnet if (json_output) 667743cc665SQuentin Monnet jsonw_start_array(json_wtr); 66871bb428fSJakub Kicinski while (true) { 66971bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 67071bb428fSJakub Kicinski if (err) { 6711739c26dSQuentin Monnet if (errno == ENOENT) { 6721739c26dSQuentin Monnet err = 0; 67371bb428fSJakub Kicinski break; 6741739c26dSQuentin Monnet } 6759a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6769a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 677743cc665SQuentin Monnet err = -1; 678743cc665SQuentin Monnet break; 67971bb428fSJakub Kicinski } 68071bb428fSJakub Kicinski 68171bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 68271bb428fSJakub Kicinski if (fd < 0) { 6838207c6ddSJakub Kicinski if (errno == ENOENT) 6848207c6ddSJakub Kicinski continue; 6859a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 68671bb428fSJakub Kicinski id, strerror(errno)); 687743cc665SQuentin Monnet err = -1; 688743cc665SQuentin Monnet break; 68971bb428fSJakub Kicinski } 69071bb428fSJakub Kicinski 69171bb428fSJakub Kicinski err = show_prog(fd); 69271bb428fSJakub Kicinski close(fd); 69371bb428fSJakub Kicinski if (err) 694743cc665SQuentin Monnet break; 69571bb428fSJakub Kicinski } 69671bb428fSJakub Kicinski 697743cc665SQuentin Monnet if (json_output) 698743cc665SQuentin Monnet jsonw_end_array(json_wtr); 699743cc665SQuentin Monnet 700d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 701d53dee3fSAndrii Nakryiko 70246241271SQuentin Monnet if (show_pinned) 7038f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 70446241271SQuentin Monnet 705743cc665SQuentin Monnet return err; 70671bb428fSJakub Kicinski } 70771bb428fSJakub Kicinski 708ec202509SPaul Chaignon static int 709ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 710ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 71171bb428fSJakub Kicinski { 712b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 7133ddeac67SJakub Kicinski const char *disasm_opt = NULL; 7147105e828SDaniel Borkmann struct dump_data dd = {}; 715cae73f23SSong Liu void *func_info = NULL; 716254471e5SYonghong Song struct btf *btf = NULL; 717254471e5SYonghong Song char func_sig[1024]; 71871bb428fSJakub Kicinski unsigned char *buf; 719cae73f23SSong Liu __u32 member_len; 720ebbd7f64SQuentin Monnet int fd, err = -1; 72171bb428fSJakub Kicinski ssize_t n; 72271bb428fSJakub Kicinski 723cae73f23SSong Liu if (mode == DUMP_JITED) { 7245b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 7259a5ab8bfSQuentin Monnet p_info("no instructions returned"); 726ec202509SPaul Chaignon return -1; 727f84192eeSSandipan Das } 72809f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 729cae73f23SSong Liu member_len = info->jited_prog_len; 730cae73f23SSong Liu } else { /* DUMP_XLATED */ 731d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7327105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 733ec202509SPaul Chaignon return -1; 7347105e828SDaniel Borkmann } 73509f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 736cae73f23SSong Liu member_len = info->xlated_prog_len; 737cae73f23SSong Liu } 7387105e828SDaniel Borkmann 73986f4b7f2SQuentin Monnet if (info->btf_id) { 74086f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 74186f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 742254471e5SYonghong Song p_err("failed to get btf"); 743ec202509SPaul Chaignon return -1; 744254471e5SYonghong Song } 74586f4b7f2SQuentin Monnet } 746254471e5SYonghong Song 74709f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 748cae73f23SSong Liu 749cae73f23SSong Liu if (info->nr_line_info) { 750cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 751b053b439SMartin KaFai Lau if (!prog_linfo) 75210a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 753b053b439SMartin KaFai Lau } 754b053b439SMartin KaFai Lau 75571bb428fSJakub Kicinski if (filepath) { 75671bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 75771bb428fSJakub Kicinski if (fd < 0) { 7589a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 75971bb428fSJakub Kicinski strerror(errno)); 760ebbd7f64SQuentin Monnet goto exit_free; 76171bb428fSJakub Kicinski } 76271bb428fSJakub Kicinski 763cae73f23SSong Liu n = write(fd, buf, member_len); 76471bb428fSJakub Kicinski close(fd); 76509f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7669a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 76771bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 768ebbd7f64SQuentin Monnet goto exit_free; 76971bb428fSJakub Kicinski } 77052c84d36SQuentin Monnet 77152c84d36SQuentin Monnet if (json_output) 77252c84d36SQuentin Monnet jsonw_null(json_wtr); 773cae73f23SSong Liu } else if (mode == DUMP_JITED) { 774e6593596SJiong Wang const char *name = NULL; 775e6593596SJiong Wang 776cae73f23SSong Liu if (info->ifindex) { 777cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 778cae73f23SSong Liu info->netns_dev, 779cae73f23SSong Liu info->netns_ino, 7803ddeac67SJakub Kicinski &disasm_opt); 781e6593596SJiong Wang if (!name) 782ebbd7f64SQuentin Monnet goto exit_free; 783e6593596SJiong Wang } 784e6593596SJiong Wang 785cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 786f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 787254471e5SYonghong Song struct bpf_func_info *record; 788f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 789f7f62c71SSandipan Das unsigned char *img = buf; 790f7f62c71SSandipan Das __u64 *ksyms = NULL; 791f7f62c71SSandipan Das __u32 *lens; 792f7f62c71SSandipan Das __u32 i; 793cae73f23SSong Liu if (info->nr_jited_ksyms) { 794f7f62c71SSandipan Das kernel_syms_load(&dd); 79509f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 796f7f62c71SSandipan Das } 797f7f62c71SSandipan Das 798f7f62c71SSandipan Das if (json_output) 799f7f62c71SSandipan Das jsonw_start_array(json_wtr); 800f7f62c71SSandipan Das 80109f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 802cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 803f7f62c71SSandipan Das if (ksyms) { 804f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 805f7f62c71SSandipan Das if (sym) 806f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 807f7f62c71SSandipan Das else 808f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 809f7f62c71SSandipan Das } else { 810f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 811f7f62c71SSandipan Das } 812f7f62c71SSandipan Das 813254471e5SYonghong Song if (func_info) { 814cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 815254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 816254471e5SYonghong Song func_sig, 817254471e5SYonghong Song sizeof(func_sig)); 818254471e5SYonghong Song } 819254471e5SYonghong Song 820f7f62c71SSandipan Das if (json_output) { 821f7f62c71SSandipan Das jsonw_start_object(json_wtr); 822254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 823254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 824254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 825254471e5SYonghong Song } 826f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 827f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 828f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 829f7f62c71SSandipan Das } else { 830254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 831254471e5SYonghong Song printf("%s:\n", func_sig); 832f7f62c71SSandipan Das printf("%s:\n", sym_name); 833f7f62c71SSandipan Das } 834f7f62c71SSandipan Das 835b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 836b053b439SMartin KaFai Lau name, disasm_opt, btf, 837b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 838b053b439SMartin KaFai Lau linum); 839b053b439SMartin KaFai Lau 840f7f62c71SSandipan Das img += lens[i]; 841f7f62c71SSandipan Das 842f7f62c71SSandipan Das if (json_output) 843f7f62c71SSandipan Das jsonw_end_object(json_wtr); 844f7f62c71SSandipan Das else 845f7f62c71SSandipan Das printf("\n"); 846f7f62c71SSandipan Das } 847f7f62c71SSandipan Das 848f7f62c71SSandipan Das if (json_output) 849f7f62c71SSandipan Das jsonw_end_array(json_wtr); 850f7f62c71SSandipan Das } else { 851cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 852b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 853f7f62c71SSandipan Das } 854b6c1cedbSJiong Wang } else if (visual) { 855b6c1cedbSJiong Wang if (json_output) 856b6c1cedbSJiong Wang jsonw_null(json_wtr); 857b6c1cedbSJiong Wang else 858cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 8597105e828SDaniel Borkmann } else { 8607105e828SDaniel Borkmann kernel_syms_load(&dd); 861cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 86209f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 863254471e5SYonghong Song dd.btf = btf; 864254471e5SYonghong Song dd.func_info = func_info; 865cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 866b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 867f84192eeSSandipan Das 868f05e2c32SQuentin Monnet if (json_output) 869cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 870b053b439SMartin KaFai Lau linum); 871f05e2c32SQuentin Monnet else 872cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 873b053b439SMartin KaFai Lau linum); 8747105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8757105e828SDaniel Borkmann } 87671bb428fSJakub Kicinski 877ebbd7f64SQuentin Monnet err = 0; 878369e955bSQuentin Monnet 879ebbd7f64SQuentin Monnet exit_free: 880ebbd7f64SQuentin Monnet btf__free(btf); 881ebbd7f64SQuentin Monnet bpf_prog_linfo__free(prog_linfo); 882ebbd7f64SQuentin Monnet return err; 883ec202509SPaul Chaignon } 88471bb428fSJakub Kicinski 885ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 886ec202509SPaul Chaignon { 887c59765cfSDave Marchevsky struct bpf_prog_info info; 888c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 889c59765cfSDave Marchevsky size_t info_data_sz = 0; 890c59765cfSDave Marchevsky void *info_data = NULL; 891ec202509SPaul Chaignon char *filepath = NULL; 892ec202509SPaul Chaignon bool opcodes = false; 893ec202509SPaul Chaignon bool visual = false; 894ec202509SPaul Chaignon enum dump_mode mode; 895ec202509SPaul Chaignon bool linum = false; 896ec202509SPaul Chaignon int nb_fds, i = 0; 897c59765cfSDave Marchevsky int *fds = NULL; 898ec202509SPaul Chaignon int err = -1; 899ec202509SPaul Chaignon 900ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 901ec202509SPaul Chaignon if (disasm_init()) 90271bb428fSJakub Kicinski return -1; 903ec202509SPaul Chaignon mode = DUMP_JITED; 904ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 905ec202509SPaul Chaignon mode = DUMP_XLATED; 906ec202509SPaul Chaignon } else { 907ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 908ec202509SPaul Chaignon return -1; 909ec202509SPaul Chaignon } 910ec202509SPaul Chaignon NEXT_ARG(); 911ec202509SPaul Chaignon 912ec202509SPaul Chaignon if (argc < 2) 913ec202509SPaul Chaignon usage(); 914ec202509SPaul Chaignon 915ec202509SPaul Chaignon fds = malloc(sizeof(int)); 916ec202509SPaul Chaignon if (!fds) { 917ec202509SPaul Chaignon p_err("mem alloc failed"); 918ec202509SPaul Chaignon return -1; 919ec202509SPaul Chaignon } 920ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 921ec202509SPaul Chaignon if (nb_fds < 1) 922ec202509SPaul Chaignon goto exit_free; 923ec202509SPaul Chaignon 924ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 925ec202509SPaul Chaignon NEXT_ARG(); 926ec202509SPaul Chaignon if (!argc) { 927ec202509SPaul Chaignon p_err("expected file path"); 928ec202509SPaul Chaignon goto exit_close; 929ec202509SPaul Chaignon } 930ec202509SPaul Chaignon if (nb_fds > 1) { 931ec202509SPaul Chaignon p_err("several programs matched"); 932ec202509SPaul Chaignon goto exit_close; 933ec202509SPaul Chaignon } 934ec202509SPaul Chaignon 935ec202509SPaul Chaignon filepath = *argv; 936ec202509SPaul Chaignon NEXT_ARG(); 937ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 938ec202509SPaul Chaignon opcodes = true; 939ec202509SPaul Chaignon NEXT_ARG(); 940ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 941ec202509SPaul Chaignon if (nb_fds > 1) { 942ec202509SPaul Chaignon p_err("several programs matched"); 943ec202509SPaul Chaignon goto exit_close; 944ec202509SPaul Chaignon } 945ec202509SPaul Chaignon 946ec202509SPaul Chaignon visual = true; 947ec202509SPaul Chaignon NEXT_ARG(); 948ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 949ec202509SPaul Chaignon linum = true; 950ec202509SPaul Chaignon NEXT_ARG(); 951ec202509SPaul Chaignon } 952ec202509SPaul Chaignon 953ec202509SPaul Chaignon if (argc) { 954ec202509SPaul Chaignon usage(); 955ec202509SPaul Chaignon goto exit_close; 956ec202509SPaul Chaignon } 957ec202509SPaul Chaignon 958ec202509SPaul Chaignon if (json_output && nb_fds > 1) 959ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 960ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 961c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 962c59765cfSDave Marchevsky 963c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 964c59765cfSDave Marchevsky if (err) { 965c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 966c59765cfSDave Marchevsky break; 967c59765cfSDave Marchevsky } 968c59765cfSDave Marchevsky 969c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 970c59765cfSDave Marchevsky if (err) { 971c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 972c59765cfSDave Marchevsky break; 973c59765cfSDave Marchevsky } 974c59765cfSDave Marchevsky 975c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 976c59765cfSDave Marchevsky if (err) { 977ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 978ec202509SPaul Chaignon break; 979ec202509SPaul Chaignon } 980ec202509SPaul Chaignon 981ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 982ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 983*b662000aSRaman Shukhau print_prog_header_json(&info, fds[i]); 984ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 985ec202509SPaul Chaignon } else if (nb_fds > 1) { 986*b662000aSRaman Shukhau print_prog_header_plain(&info, fds[i]); 987ec202509SPaul Chaignon } 988ec202509SPaul Chaignon 989c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 990ec202509SPaul Chaignon 991ec202509SPaul Chaignon if (json_output && nb_fds > 1) 992ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 993ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 994ec202509SPaul Chaignon printf("\n"); 995ec202509SPaul Chaignon 996ec202509SPaul Chaignon if (err) 997ec202509SPaul Chaignon break; 998ec202509SPaul Chaignon close(fds[i]); 999ec202509SPaul Chaignon } 1000ec202509SPaul Chaignon if (json_output && nb_fds > 1) 1001ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 1002ec202509SPaul Chaignon 1003ec202509SPaul Chaignon exit_close: 1004ec202509SPaul Chaignon for (; i < nb_fds; i++) 1005ec202509SPaul Chaignon close(fds[i]); 1006ec202509SPaul Chaignon exit_free: 1007c59765cfSDave Marchevsky free(info_data); 1008ec202509SPaul Chaignon free(fds); 1009ec202509SPaul Chaignon return err; 101071bb428fSJakub Kicinski } 101171bb428fSJakub Kicinski 101271bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 101371bb428fSJakub Kicinski { 1014004b45c0SQuentin Monnet int err; 1015004b45c0SQuentin Monnet 101675a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 1017004b45c0SQuentin Monnet if (!err && json_output) 1018004b45c0SQuentin Monnet jsonw_null(json_wtr); 1019004b45c0SQuentin Monnet return err; 102071bb428fSJakub Kicinski } 102171bb428fSJakub Kicinski 10223ff5a4dcSJakub Kicinski struct map_replace { 10233ff5a4dcSJakub Kicinski int idx; 10243ff5a4dcSJakub Kicinski int fd; 10253ff5a4dcSJakub Kicinski char *name; 10263ff5a4dcSJakub Kicinski }; 10273ff5a4dcSJakub Kicinski 1028c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 10293ff5a4dcSJakub Kicinski { 10303ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10313ff5a4dcSJakub Kicinski 10323ff5a4dcSJakub Kicinski return a->idx - b->idx; 10333ff5a4dcSJakub Kicinski } 10343ff5a4dcSJakub Kicinski 1035092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1036092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1037092f0892SStanislav Fomichev int *mapfd) 1038092f0892SStanislav Fomichev { 1039092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1040092f0892SStanislav Fomichev return -EINVAL; 1041092f0892SStanislav Fomichev 1042092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1043092f0892SStanislav Fomichev if (*progfd < 0) 1044092f0892SStanislav Fomichev return *progfd; 1045092f0892SStanislav Fomichev 1046092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1047092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1048092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1049092f0892SStanislav Fomichev return -EINVAL; 1050092f0892SStanislav Fomichev } 1051092f0892SStanislav Fomichev 1052092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1053f9b7ff0dSLorenz Bauer *mapfd = 0; 1054092f0892SStanislav Fomichev return 0; 1055092f0892SStanislav Fomichev } 1056092f0892SStanislav Fomichev 1057092f0892SStanislav Fomichev NEXT_ARG(); 1058092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1059092f0892SStanislav Fomichev return -EINVAL; 1060092f0892SStanislav Fomichev 1061092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1062092f0892SStanislav Fomichev if (*mapfd < 0) 1063092f0892SStanislav Fomichev return *mapfd; 1064092f0892SStanislav Fomichev 1065092f0892SStanislav Fomichev return 0; 1066092f0892SStanislav Fomichev } 1067092f0892SStanislav Fomichev 1068b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1069b7d3826cSJohn Fastabend { 1070b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1071092f0892SStanislav Fomichev int err, progfd; 1072092f0892SStanislav Fomichev int mapfd; 1073b7d3826cSJohn Fastabend 1074092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1075092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1076092f0892SStanislav Fomichev if (err) 1077092f0892SStanislav Fomichev return err; 1078b7d3826cSJohn Fastabend 1079b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1080b7d3826cSJohn Fastabend if (err) { 1081b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1082b7d3826cSJohn Fastabend return -EINVAL; 1083b7d3826cSJohn Fastabend } 1084b7d3826cSJohn Fastabend 1085b7d3826cSJohn Fastabend if (json_output) 1086b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1087b7d3826cSJohn Fastabend return 0; 1088b7d3826cSJohn Fastabend } 1089b7d3826cSJohn Fastabend 1090b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1091b7d3826cSJohn Fastabend { 1092b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1093092f0892SStanislav Fomichev int err, progfd; 1094092f0892SStanislav Fomichev int mapfd; 1095b7d3826cSJohn Fastabend 1096092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1097092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1098092f0892SStanislav Fomichev if (err) 1099092f0892SStanislav Fomichev return err; 1100b7d3826cSJohn Fastabend 1101b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1102b7d3826cSJohn Fastabend if (err) { 1103b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1104b7d3826cSJohn Fastabend return -EINVAL; 1105b7d3826cSJohn Fastabend } 1106b7d3826cSJohn Fastabend 1107b7d3826cSJohn Fastabend if (json_output) 1108b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1109b7d3826cSJohn Fastabend return 0; 1110b7d3826cSJohn Fastabend } 111177380998SStanislav Fomichev 1112ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1113ba95c745SQuentin Monnet { 1114ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1115ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1116ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1117ba95c745SQuentin Monnet return -1; 1118ba95c745SQuentin Monnet } 1119ba95c745SQuentin Monnet 1120ba95c745SQuentin Monnet return 0; 1121ba95c745SQuentin Monnet } 1122ba95c745SQuentin Monnet 1123ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1124ba95c745SQuentin Monnet { 1125ba95c745SQuentin Monnet size_t block_size = 256; 1126ba95c745SQuentin Monnet size_t buf_size = block_size; 1127ba95c745SQuentin Monnet size_t nb_read = 0; 1128ba95c745SQuentin Monnet void *tmp; 1129ba95c745SQuentin Monnet FILE *f; 1130ba95c745SQuentin Monnet 1131ba95c745SQuentin Monnet if (!fname) { 1132ba95c745SQuentin Monnet *data_ptr = NULL; 1133ba95c745SQuentin Monnet *size = 0; 1134ba95c745SQuentin Monnet return 0; 1135ba95c745SQuentin Monnet } 1136ba95c745SQuentin Monnet 1137ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1138ba95c745SQuentin Monnet f = stdin; 1139ba95c745SQuentin Monnet else 1140ba95c745SQuentin Monnet f = fopen(fname, "r"); 1141ba95c745SQuentin Monnet if (!f) { 1142ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1143ba95c745SQuentin Monnet return -1; 1144ba95c745SQuentin Monnet } 1145ba95c745SQuentin Monnet 1146ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1147ba95c745SQuentin Monnet if (!*data_ptr) { 1148ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1149ba95c745SQuentin Monnet strerror(errno)); 1150ba95c745SQuentin Monnet goto err_fclose; 1151ba95c745SQuentin Monnet } 1152ba95c745SQuentin Monnet 1153ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1154ba95c745SQuentin Monnet if (feof(f)) 1155ba95c745SQuentin Monnet break; 1156ba95c745SQuentin Monnet if (ferror(f)) { 1157ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1158ba95c745SQuentin Monnet fname, strerror(errno)); 1159ba95c745SQuentin Monnet goto err_free; 1160ba95c745SQuentin Monnet } 1161ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1162ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1163ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1164ba95c745SQuentin Monnet UINT32_MAX); 1165ba95c745SQuentin Monnet goto err_free; 1166ba95c745SQuentin Monnet } 1167ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1168ba95c745SQuentin Monnet buf_size *= 2; 1169ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1170ba95c745SQuentin Monnet if (!tmp) { 1171ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1172ba95c745SQuentin Monnet strerror(errno)); 1173ba95c745SQuentin Monnet goto err_free; 1174ba95c745SQuentin Monnet } 1175ba95c745SQuentin Monnet *data_ptr = tmp; 1176ba95c745SQuentin Monnet } 1177ba95c745SQuentin Monnet } 1178ba95c745SQuentin Monnet if (f != stdin) 1179ba95c745SQuentin Monnet fclose(f); 1180ba95c745SQuentin Monnet 1181ba95c745SQuentin Monnet *size = nb_read; 1182ba95c745SQuentin Monnet return 0; 1183ba95c745SQuentin Monnet 1184ba95c745SQuentin Monnet err_free: 1185ba95c745SQuentin Monnet free(*data_ptr); 1186ba95c745SQuentin Monnet *data_ptr = NULL; 1187ba95c745SQuentin Monnet err_fclose: 1188ba95c745SQuentin Monnet if (f != stdin) 1189ba95c745SQuentin Monnet fclose(f); 1190ba95c745SQuentin Monnet return -1; 1191ba95c745SQuentin Monnet } 1192ba95c745SQuentin Monnet 1193ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1194ba95c745SQuentin Monnet { 1195ba95c745SQuentin Monnet size_t i, j; 1196ba95c745SQuentin Monnet char c; 1197ba95c745SQuentin Monnet 1198ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1199ba95c745SQuentin Monnet /* Row offset */ 1200ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1201ba95c745SQuentin Monnet 1202ba95c745SQuentin Monnet /* Hexadecimal values */ 1203ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1204ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1205ba95c745SQuentin Monnet j % 2 ? " " : ""); 1206ba95c745SQuentin Monnet for (; j < i + 16; j++) 1207ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1208ba95c745SQuentin Monnet 1209ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1210ba95c745SQuentin Monnet fprintf(f, "| "); 1211ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1212ba95c745SQuentin Monnet c = *(char *)(data + j); 1213ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1214ba95c745SQuentin Monnet c = '.'; 1215ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1216ba95c745SQuentin Monnet } 1217ba95c745SQuentin Monnet 1218ba95c745SQuentin Monnet fprintf(f, "\n"); 1219ba95c745SQuentin Monnet } 1220ba95c745SQuentin Monnet } 1221ba95c745SQuentin Monnet 1222ba95c745SQuentin Monnet static int 1223ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1224ba95c745SQuentin Monnet const char *json_key) 1225ba95c745SQuentin Monnet { 1226ba95c745SQuentin Monnet size_t nb_written; 1227ba95c745SQuentin Monnet FILE *f; 1228ba95c745SQuentin Monnet 1229ba95c745SQuentin Monnet if (!fname) 1230ba95c745SQuentin Monnet return 0; 1231ba95c745SQuentin Monnet 1232ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1233ba95c745SQuentin Monnet f = stdout; 1234ba95c745SQuentin Monnet if (json_output) { 1235ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1236ba95c745SQuentin Monnet print_data_json(data, size); 1237ba95c745SQuentin Monnet } else { 1238ba95c745SQuentin Monnet hex_print(data, size, f); 1239ba95c745SQuentin Monnet } 1240ba95c745SQuentin Monnet return 0; 1241ba95c745SQuentin Monnet } 1242ba95c745SQuentin Monnet 1243ba95c745SQuentin Monnet f = fopen(fname, "w"); 1244ba95c745SQuentin Monnet if (!f) { 1245ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1246ba95c745SQuentin Monnet return -1; 1247ba95c745SQuentin Monnet } 1248ba95c745SQuentin Monnet 1249ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1250ba95c745SQuentin Monnet fclose(f); 1251ba95c745SQuentin Monnet if (nb_written != size) { 1252ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1253ba95c745SQuentin Monnet return -1; 1254ba95c745SQuentin Monnet } 1255ba95c745SQuentin Monnet 1256ba95c745SQuentin Monnet return 0; 1257ba95c745SQuentin Monnet } 1258ba95c745SQuentin Monnet 1259ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1260ba95c745SQuentin Monnet { 1261ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1262ba95c745SQuentin Monnet if (!*data_ptr) { 1263ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1264ba95c745SQuentin Monnet strerror(errno)); 1265ba95c745SQuentin Monnet return -1; 1266ba95c745SQuentin Monnet } 1267ba95c745SQuentin Monnet 1268ba95c745SQuentin Monnet return 0; 1269ba95c745SQuentin Monnet } 1270ba95c745SQuentin Monnet 1271ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1272ba95c745SQuentin Monnet { 1273ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1274ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1275ba95c745SQuentin Monnet struct bpf_prog_test_run_attr test_attr = {0}; 1276ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1277ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1278ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1279ba95c745SQuentin Monnet unsigned int repeat = 1; 1280ba95c745SQuentin Monnet int fd, err; 1281ba95c745SQuentin Monnet 1282ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1283ba95c745SQuentin Monnet return -1; 1284ba95c745SQuentin Monnet 1285ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1286ba95c745SQuentin Monnet if (fd < 0) 1287ba95c745SQuentin Monnet return -1; 1288ba95c745SQuentin Monnet 1289ba95c745SQuentin Monnet while (argc) { 1290ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1291ba95c745SQuentin Monnet "data_size_out", NULL)) 1292ba95c745SQuentin Monnet return -1; 1293ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1294ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1295ba95c745SQuentin Monnet return -1; 1296ba95c745SQuentin Monnet 1297ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1298ba95c745SQuentin Monnet NEXT_ARG(); 1299ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1300ba95c745SQuentin Monnet return -1; 1301ba95c745SQuentin Monnet 1302ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1303ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1304ba95c745SQuentin Monnet return -1; 1305ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1306ba95c745SQuentin Monnet NEXT_ARG(); 1307ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1308ba95c745SQuentin Monnet return -1; 1309ba95c745SQuentin Monnet 1310ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1311ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1312ba95c745SQuentin Monnet char *endptr; 1313ba95c745SQuentin Monnet 1314ba95c745SQuentin Monnet NEXT_ARG(); 1315ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1316ba95c745SQuentin Monnet return -1; 1317ba95c745SQuentin Monnet 1318ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1319ba95c745SQuentin Monnet if (*endptr) { 1320ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1321ba95c745SQuentin Monnet *argv); 1322ba95c745SQuentin Monnet return -1; 1323ba95c745SQuentin Monnet } 1324ba95c745SQuentin Monnet NEXT_ARG(); 1325ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1326ba95c745SQuentin Monnet NEXT_ARG(); 1327ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1328ba95c745SQuentin Monnet return -1; 1329ba95c745SQuentin Monnet 1330ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1331ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1332ba95c745SQuentin Monnet return -1; 1333ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1334ba95c745SQuentin Monnet NEXT_ARG(); 1335ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1336ba95c745SQuentin Monnet return -1; 1337ba95c745SQuentin Monnet 1338ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1339ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1340ba95c745SQuentin Monnet char *endptr; 1341ba95c745SQuentin Monnet 1342ba95c745SQuentin Monnet NEXT_ARG(); 1343ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1344ba95c745SQuentin Monnet return -1; 1345ba95c745SQuentin Monnet 1346ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1347ba95c745SQuentin Monnet if (*endptr) { 1348ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1349ba95c745SQuentin Monnet *argv); 1350ba95c745SQuentin Monnet return -1; 1351ba95c745SQuentin Monnet } 1352ba95c745SQuentin Monnet NEXT_ARG(); 1353ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1354ba95c745SQuentin Monnet char *endptr; 1355ba95c745SQuentin Monnet 1356ba95c745SQuentin Monnet NEXT_ARG(); 1357ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1358ba95c745SQuentin Monnet return -1; 1359ba95c745SQuentin Monnet 1360ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1361ba95c745SQuentin Monnet if (*endptr) { 1362ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1363ba95c745SQuentin Monnet *argv); 1364ba95c745SQuentin Monnet return -1; 1365ba95c745SQuentin Monnet } 1366ba95c745SQuentin Monnet NEXT_ARG(); 1367ba95c745SQuentin Monnet } else { 1368ba95c745SQuentin 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'?", 1369ba95c745SQuentin Monnet *argv); 1370ba95c745SQuentin Monnet return -1; 1371ba95c745SQuentin Monnet } 1372ba95c745SQuentin Monnet } 1373ba95c745SQuentin Monnet 1374ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1375ba95c745SQuentin Monnet if (err) 1376ba95c745SQuentin Monnet return -1; 1377ba95c745SQuentin Monnet 1378ba95c745SQuentin Monnet if (data_in) { 1379ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1380ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1381ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1382ba95c745SQuentin Monnet if (err) 1383ba95c745SQuentin Monnet goto free_data_in; 1384ba95c745SQuentin Monnet } 1385ba95c745SQuentin Monnet 1386ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1387ba95c745SQuentin Monnet if (err) 1388ba95c745SQuentin Monnet goto free_data_out; 1389ba95c745SQuentin Monnet 1390ba95c745SQuentin Monnet if (ctx_in) { 1391ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1392ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1393ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1394ba95c745SQuentin Monnet if (err) 1395ba95c745SQuentin Monnet goto free_ctx_in; 1396ba95c745SQuentin Monnet } 1397ba95c745SQuentin Monnet 1398ba95c745SQuentin Monnet test_attr.prog_fd = fd; 1399ba95c745SQuentin Monnet test_attr.repeat = repeat; 1400ba95c745SQuentin Monnet test_attr.data_in = data_in; 1401ba95c745SQuentin Monnet test_attr.data_out = data_out; 1402ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1403ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1404ba95c745SQuentin Monnet 1405ba95c745SQuentin Monnet err = bpf_prog_test_run_xattr(&test_attr); 1406ba95c745SQuentin Monnet if (err) { 1407ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1408ba95c745SQuentin Monnet goto free_ctx_out; 1409ba95c745SQuentin Monnet } 1410ba95c745SQuentin Monnet 1411ba95c745SQuentin Monnet err = 0; 1412ba95c745SQuentin Monnet 1413ba95c745SQuentin Monnet if (json_output) 1414ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1415ba95c745SQuentin Monnet 1416ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1417ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1418ba95c745SQuentin Monnet */ 1419ba95c745SQuentin Monnet if (test_attr.data_size_out) 1420ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1421ba95c745SQuentin Monnet test_attr.data_size_out, 1422ba95c745SQuentin Monnet data_fname_out, "data_out"); 1423ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1424ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1425ba95c745SQuentin Monnet test_attr.ctx_size_out, 1426ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1427ba95c745SQuentin Monnet 1428ba95c745SQuentin Monnet if (json_output) { 1429ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1430ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1431ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1432ba95c745SQuentin Monnet } else { 1433ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1434ba95c745SQuentin Monnet test_attr.retval, 1435ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1436ba95c745SQuentin Monnet } 1437ba95c745SQuentin Monnet 1438ba95c745SQuentin Monnet free_ctx_out: 1439ba95c745SQuentin Monnet free(ctx_out); 1440ba95c745SQuentin Monnet free_ctx_in: 1441ba95c745SQuentin Monnet free(ctx_in); 1442ba95c745SQuentin Monnet free_data_out: 1443ba95c745SQuentin Monnet free(data_out); 1444ba95c745SQuentin Monnet free_data_in: 1445ba95c745SQuentin Monnet free(data_in); 1446ba95c745SQuentin Monnet 1447ba95c745SQuentin Monnet return err; 1448ba95c745SQuentin Monnet } 1449ba95c745SQuentin Monnet 14506ae32b29SQuentin Monnet static int 14516ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14526ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14536ae32b29SQuentin Monnet { 14546ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14556ae32b29SQuentin Monnet int ret; 14566ae32b29SQuentin Monnet 14576ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14586ae32b29SQuentin Monnet if (!ret) 14596ae32b29SQuentin Monnet return ret; 14606ae32b29SQuentin Monnet 14616ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14626ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14636ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14646ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14656ae32b29SQuentin Monnet 14666ae32b29SQuentin Monnet return ret; 14676ae32b29SQuentin Monnet } 14686ae32b29SQuentin Monnet 146977380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 147049a086c2SRoman Gushchin { 147132e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1472e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1473e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1474e00aca65SAndrii Nakryiko ); 147555d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 14763ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 147777380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 14783ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 14793767a94bSStanislav Fomichev const char *pinmaps = NULL; 148049a086c2SRoman Gushchin struct bpf_object *obj; 1481c8406848SJakub Kicinski struct bpf_map *map; 1482c8406848SJakub Kicinski const char *pinfile; 14833ff5a4dcSJakub Kicinski unsigned int i, j; 1484c8406848SJakub Kicinski __u32 ifindex = 0; 148532e3e58eSAndrii Nakryiko const char *file; 14863ff5a4dcSJakub Kicinski int idx, err; 148749a086c2SRoman Gushchin 148832e3e58eSAndrii Nakryiko 14898d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 14908d1fc3deSJakub Kicinski return -1; 149132e3e58eSAndrii Nakryiko file = GET_ARG(); 14928d1fc3deSJakub Kicinski pinfile = GET_ARG(); 149349a086c2SRoman Gushchin 1494ba6dd679SJakub Kicinski while (argc) { 149549f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 149649f2cba3SJakub Kicinski NEXT_ARG(); 149749f2cba3SJakub Kicinski 149832e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 149949f2cba3SJakub Kicinski p_err("program type already specified"); 15003ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 150149f2cba3SJakub Kicinski } 150249f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 15033ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 150449f2cba3SJakub Kicinski 1505314f14abSStanislav Fomichev err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1506314f14abSStanislav Fomichev &expected_attach_type); 1507314f14abSStanislav Fomichev if (err < 0) { 150849f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 1509314f14abSStanislav Fomichev char *type = malloc(strlen(*argv) + 2); 1510314f14abSStanislav Fomichev 151149f2cba3SJakub Kicinski if (!type) { 151249f2cba3SJakub Kicinski p_err("mem alloc failed"); 15133ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 151449f2cba3SJakub Kicinski } 151549f2cba3SJakub Kicinski *type = 0; 151649f2cba3SJakub Kicinski strcat(type, *argv); 151749f2cba3SJakub Kicinski strcat(type, "/"); 151849f2cba3SJakub Kicinski 15196ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1520c8406848SJakub Kicinski &expected_attach_type); 152149f2cba3SJakub Kicinski free(type); 1522c76e4c22STaeung Song if (err < 0) 15233ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1524314f14abSStanislav Fomichev } 1525c76e4c22STaeung Song 152649f2cba3SJakub Kicinski NEXT_ARG(); 15273ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1528dde7011aSJakub Kicinski void *new_map_replace; 15293ff5a4dcSJakub Kicinski char *endptr, *name; 15303ff5a4dcSJakub Kicinski int fd; 15313ff5a4dcSJakub Kicinski 15323ff5a4dcSJakub Kicinski NEXT_ARG(); 15333ff5a4dcSJakub Kicinski 15343ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 15353ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15363ff5a4dcSJakub Kicinski 15373ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 15383ff5a4dcSJakub Kicinski NEXT_ARG(); 15393ff5a4dcSJakub Kicinski 15403ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 15413ff5a4dcSJakub Kicinski if (*endptr) { 15423ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 15433ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15443ff5a4dcSJakub Kicinski } 15453ff5a4dcSJakub Kicinski name = NULL; 15463ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 15473ff5a4dcSJakub Kicinski NEXT_ARG(); 15483ff5a4dcSJakub Kicinski 15493ff5a4dcSJakub Kicinski name = *argv; 15503ff5a4dcSJakub Kicinski idx = -1; 15513ff5a4dcSJakub Kicinski } else { 15523ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 15533ff5a4dcSJakub Kicinski *argv); 15543ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15553ff5a4dcSJakub Kicinski } 15563ff5a4dcSJakub Kicinski NEXT_ARG(); 15573ff5a4dcSJakub Kicinski 15583ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 15593ff5a4dcSJakub Kicinski if (fd < 0) 15603ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15613ff5a4dcSJakub Kicinski 1562dde7011aSJakub Kicinski new_map_replace = reallocarray(map_replace, 1563dde7011aSJakub Kicinski old_map_fds + 1, 15643ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1565dde7011aSJakub Kicinski if (!new_map_replace) { 15663ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 15673ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15683ff5a4dcSJakub Kicinski } 1569dde7011aSJakub Kicinski map_replace = new_map_replace; 1570dde7011aSJakub Kicinski 15713ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 15723ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 15733ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 15743ff5a4dcSJakub Kicinski old_map_fds++; 157549f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1576ba6dd679SJakub Kicinski NEXT_ARG(); 1577ba6dd679SJakub Kicinski 1578c8406848SJakub Kicinski if (ifindex) { 1579ba6dd679SJakub Kicinski p_err("offload device already specified"); 15803ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1581ba6dd679SJakub Kicinski } 1582ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 15833ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1584ba6dd679SJakub Kicinski 1585c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1586c8406848SJakub Kicinski if (!ifindex) { 1587ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1588ba6dd679SJakub Kicinski *argv, strerror(errno)); 15893ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1590ba6dd679SJakub Kicinski } 1591ba6dd679SJakub Kicinski NEXT_ARG(); 15923767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 15933767a94bSStanislav Fomichev NEXT_ARG(); 15943767a94bSStanislav Fomichev 15953767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 15963767a94bSStanislav Fomichev goto err_free_reuse_maps; 15973767a94bSStanislav Fomichev 15983767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1599ba6dd679SJakub Kicinski } else { 16003ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1601ba6dd679SJakub Kicinski *argv); 16023ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1603ba6dd679SJakub Kicinski } 1604ba6dd679SJakub Kicinski } 1605ba6dd679SJakub Kicinski 1606ac4e0e05SYonghong Song set_max_rlimit(); 1607ac4e0e05SYonghong Song 1608b59e4ce8SAndrii Nakryiko if (verifier_logs) 1609b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1610b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1611b59e4ce8SAndrii Nakryiko 161232e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1613d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1614c8406848SJakub Kicinski p_err("failed to open object file"); 16153ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 161649a086c2SRoman Gushchin } 161749a086c2SRoman Gushchin 161877380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 161932e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1620c8406848SJakub Kicinski 162132e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1622fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1623c8406848SJakub Kicinski 16246ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1625c8406848SJakub Kicinski &expected_attach_type); 1626c76e4c22STaeung Song if (err < 0) 1627c8406848SJakub Kicinski goto err_close_obj; 1628c8406848SJakub Kicinski } 162977380998SStanislav Fomichev 163077380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 163177380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 163277380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 163377380998SStanislav Fomichev } 1634c8406848SJakub Kicinski 16353ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16363ff5a4dcSJakub Kicinski map_replace_compar); 16373ff5a4dcSJakub Kicinski 16383ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 16393ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 16403ff5a4dcSJakub Kicinski */ 16413ff5a4dcSJakub Kicinski j = 0; 16423ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 16433ff5a4dcSJakub Kicinski i = 0; 1644f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16453ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 16463ff5a4dcSJakub Kicinski map_replace[j].idx = i; 16473ff5a4dcSJakub Kicinski break; 16483ff5a4dcSJakub Kicinski } 16493ff5a4dcSJakub Kicinski i++; 16503ff5a4dcSJakub Kicinski } 16513ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 16523ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 16533ff5a4dcSJakub Kicinski goto err_close_obj; 16543ff5a4dcSJakub Kicinski } 16553ff5a4dcSJakub Kicinski j++; 16563ff5a4dcSJakub Kicinski } 16573ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 16583ff5a4dcSJakub Kicinski if (j) 16593ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16603ff5a4dcSJakub Kicinski map_replace_compar); 16613ff5a4dcSJakub Kicinski 16623ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 16633ff5a4dcSJakub Kicinski j = 0; 16643ff5a4dcSJakub Kicinski idx = 0; 1665f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16669855c131SChristy Lee if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1667c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1668c8406848SJakub Kicinski 16693ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 16703ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 16713ff5a4dcSJakub Kicinski if (err) { 16723ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 16733ff5a4dcSJakub Kicinski goto err_close_obj; 16743ff5a4dcSJakub Kicinski } 16753ff5a4dcSJakub Kicinski 16763ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 16773ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 16783ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 16793ff5a4dcSJakub Kicinski idx); 16803ff5a4dcSJakub Kicinski goto err_close_obj; 16813ff5a4dcSJakub Kicinski } 16823ff5a4dcSJakub Kicinski } 16833ff5a4dcSJakub Kicinski 16843ff5a4dcSJakub Kicinski idx++; 16853ff5a4dcSJakub Kicinski } 16863ff5a4dcSJakub Kicinski if (j < old_map_fds) { 16873ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 16883ff5a4dcSJakub Kicinski goto err_close_obj; 16893ff5a4dcSJakub Kicinski } 16903ff5a4dcSJakub Kicinski 1691b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1692c8406848SJakub Kicinski if (err) { 1693c8406848SJakub Kicinski p_err("failed to load object file"); 1694c8406848SJakub Kicinski goto err_close_obj; 1695c8406848SJakub Kicinski } 1696c8406848SJakub Kicinski 169777380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 169877380998SStanislav Fomichev if (err) 1699bfee71fbSJakub Kicinski goto err_close_obj; 170049a086c2SRoman Gushchin 170177380998SStanislav Fomichev if (first_prog_only) { 17026f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 170377380998SStanislav Fomichev if (!prog) { 170477380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 170577380998SStanislav Fomichev goto err_close_obj; 170677380998SStanislav Fomichev } 170777380998SStanislav Fomichev 170877380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 170977380998SStanislav Fomichev if (err) { 171077380998SStanislav Fomichev p_err("failed to pin program %s", 1711fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 171277380998SStanislav Fomichev goto err_close_obj; 171377380998SStanislav Fomichev } 171477380998SStanislav Fomichev } else { 171577380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 171677380998SStanislav Fomichev if (err) { 171777380998SStanislav Fomichev p_err("failed to pin all programs"); 171877380998SStanislav Fomichev goto err_close_obj; 171977380998SStanislav Fomichev } 172077380998SStanislav Fomichev } 172177380998SStanislav Fomichev 17223767a94bSStanislav Fomichev if (pinmaps) { 17233767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 17243767a94bSStanislav Fomichev if (err) { 17253767a94bSStanislav Fomichev p_err("failed to pin all maps"); 17263767a94bSStanislav Fomichev goto err_unpin; 17273767a94bSStanislav Fomichev } 17283767a94bSStanislav Fomichev } 17293767a94bSStanislav Fomichev 173049a086c2SRoman Gushchin if (json_output) 173149a086c2SRoman Gushchin jsonw_null(json_wtr); 173249a086c2SRoman Gushchin 1733bfee71fbSJakub Kicinski bpf_object__close(obj); 17343ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17353ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17363ff5a4dcSJakub Kicinski free(map_replace); 1737bfee71fbSJakub Kicinski 173849a086c2SRoman Gushchin return 0; 1739bfee71fbSJakub Kicinski 17403767a94bSStanislav Fomichev err_unpin: 17413767a94bSStanislav Fomichev if (first_prog_only) 17423767a94bSStanislav Fomichev unlink(pinfile); 17433767a94bSStanislav Fomichev else 17443767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1745bfee71fbSJakub Kicinski err_close_obj: 1746314f14abSStanislav Fomichev if (!legacy_libbpf) { 1747314f14abSStanislav Fomichev p_info("Warning: bpftool is now running in libbpf strict mode and has more stringent requirements about BPF programs.\n" 1748314f14abSStanislav Fomichev "If it used to work for this object file but now doesn't, see --legacy option for more details.\n"); 1749314f14abSStanislav Fomichev } 1750314f14abSStanislav Fomichev 1751bfee71fbSJakub Kicinski bpf_object__close(obj); 17523ff5a4dcSJakub Kicinski err_free_reuse_maps: 17533ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17543ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17553ff5a4dcSJakub Kicinski free(map_replace); 1756bfee71fbSJakub Kicinski return -1; 175749a086c2SRoman Gushchin } 175849a086c2SRoman Gushchin 1759d510296dSAlexei Starovoitov static int count_open_fds(void) 1760d510296dSAlexei Starovoitov { 1761d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1762d510296dSAlexei Starovoitov struct dirent *de; 1763d510296dSAlexei Starovoitov int cnt = -3; 1764d510296dSAlexei Starovoitov 1765d510296dSAlexei Starovoitov if (!dp) 1766d510296dSAlexei Starovoitov return -1; 1767d510296dSAlexei Starovoitov 1768d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1769d510296dSAlexei Starovoitov cnt++; 1770d510296dSAlexei Starovoitov 1771d510296dSAlexei Starovoitov closedir(dp); 1772d510296dSAlexei Starovoitov return cnt; 1773d510296dSAlexei Starovoitov } 1774d510296dSAlexei Starovoitov 1775d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1776d510296dSAlexei Starovoitov { 1777d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1778d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1779d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1780d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1781d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1782d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1783942df4dcSAlexei Starovoitov char *log_buf = NULL; 1784d510296dSAlexei Starovoitov 1785d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1786d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1787d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1788942df4dcSAlexei Starovoitov if (verifier_logs) { 1789942df4dcSAlexei Starovoitov ctx->log_level = 1 + 2 + 4; 1790d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1791d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1792d510296dSAlexei Starovoitov if (!log_buf) 1793d510296dSAlexei Starovoitov return -ENOMEM; 1794d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1795942df4dcSAlexei Starovoitov } 1796d510296dSAlexei Starovoitov opts.ctx = ctx; 1797d510296dSAlexei Starovoitov opts.data = gen->data; 1798d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1799d510296dSAlexei Starovoitov opts.insns = gen->insns; 1800d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1801d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1802d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1803d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1804942df4dcSAlexei Starovoitov if (err < 0 || verifier_logs) { 1805d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1806942df4dcSAlexei Starovoitov if (fd_delta && err < 0) 1807d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1808d510296dSAlexei Starovoitov fd_delta); 1809d510296dSAlexei Starovoitov } 1810d510296dSAlexei Starovoitov free(log_buf); 1811d510296dSAlexei Starovoitov return err; 1812d510296dSAlexei Starovoitov } 1813d510296dSAlexei Starovoitov 1814d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1815d510296dSAlexei Starovoitov { 1816d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1817d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1818d510296dSAlexei Starovoitov struct bpf_object *obj; 1819d510296dSAlexei Starovoitov const char *file; 1820d510296dSAlexei Starovoitov int err = 0; 1821d510296dSAlexei Starovoitov 1822d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1823d510296dSAlexei Starovoitov return -1; 1824d510296dSAlexei Starovoitov file = GET_ARG(); 1825d510296dSAlexei Starovoitov 1826b59e4ce8SAndrii Nakryiko if (verifier_logs) 1827b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1828b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1829b59e4ce8SAndrii Nakryiko 1830d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1831d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1832d510296dSAlexei Starovoitov p_err("failed to open object file"); 1833d510296dSAlexei Starovoitov goto err_close_obj; 1834d510296dSAlexei Starovoitov } 1835d510296dSAlexei Starovoitov 1836d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1837d510296dSAlexei Starovoitov if (err) 1838d510296dSAlexei Starovoitov goto err_close_obj; 1839d510296dSAlexei Starovoitov 1840b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1841d510296dSAlexei Starovoitov if (err) { 1842d510296dSAlexei Starovoitov p_err("failed to load object file"); 1843d510296dSAlexei Starovoitov goto err_close_obj; 1844d510296dSAlexei Starovoitov } 1845d510296dSAlexei Starovoitov 1846d510296dSAlexei Starovoitov if (verifier_logs) { 1847d510296dSAlexei Starovoitov struct dump_data dd = {}; 1848d510296dSAlexei Starovoitov 1849d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1850d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1851d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1852d510296dSAlexei Starovoitov } 1853d510296dSAlexei Starovoitov err = try_loader(&gen); 1854d510296dSAlexei Starovoitov err_close_obj: 1855d510296dSAlexei Starovoitov bpf_object__close(obj); 1856d510296dSAlexei Starovoitov return err; 1857d510296dSAlexei Starovoitov } 1858d510296dSAlexei Starovoitov 185977380998SStanislav Fomichev static int do_load(int argc, char **argv) 186077380998SStanislav Fomichev { 1861d510296dSAlexei Starovoitov if (use_loader) 1862d510296dSAlexei Starovoitov return do_loader(argc, argv); 186377380998SStanislav Fomichev return load_with_options(argc, argv, true); 186477380998SStanislav Fomichev } 186577380998SStanislav Fomichev 186677380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 186777380998SStanislav Fomichev { 186877380998SStanislav Fomichev return load_with_options(argc, argv, false); 186977380998SStanislav Fomichev } 187077380998SStanislav Fomichev 187147c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 187247c09d6aSSong Liu 187347c09d6aSSong Liu static int do_profile(int argc, char **argv) 187447c09d6aSSong Liu { 187514e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 187647c09d6aSSong Liu return 0; 187747c09d6aSSong Liu } 187847c09d6aSSong Liu 187947c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 188047c09d6aSSong Liu 188147c09d6aSSong Liu #include "profiler.skel.h" 188247c09d6aSSong Liu 188347c09d6aSSong Liu struct profile_metric { 188447c09d6aSSong Liu const char *name; 188547c09d6aSSong Liu struct bpf_perf_event_value val; 188647c09d6aSSong Liu struct perf_event_attr attr; 188747c09d6aSSong Liu bool selected; 188847c09d6aSSong Liu 188947c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 189047c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 189147c09d6aSSong Liu const char *ratio_desc; 189247c09d6aSSong Liu const float ratio_mul; 189347c09d6aSSong Liu } metrics[] = { 189447c09d6aSSong Liu { 189547c09d6aSSong Liu .name = "cycles", 189647c09d6aSSong Liu .attr = { 189747c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 189847c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 189947c09d6aSSong Liu .exclude_user = 1, 190047c09d6aSSong Liu }, 190147c09d6aSSong Liu }, 190247c09d6aSSong Liu { 190347c09d6aSSong Liu .name = "instructions", 190447c09d6aSSong Liu .attr = { 190547c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 190647c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 190747c09d6aSSong Liu .exclude_user = 1, 190847c09d6aSSong Liu }, 190947c09d6aSSong Liu .ratio_metric = 1, 191047c09d6aSSong Liu .ratio_desc = "insns per cycle", 191147c09d6aSSong Liu .ratio_mul = 1.0, 191247c09d6aSSong Liu }, 191347c09d6aSSong Liu { 191447c09d6aSSong Liu .name = "l1d_loads", 191547c09d6aSSong Liu .attr = { 191647c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 191747c09d6aSSong Liu .config = 191847c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 191947c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 192047c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 192147c09d6aSSong Liu .exclude_user = 1, 192247c09d6aSSong Liu }, 192347c09d6aSSong Liu }, 192447c09d6aSSong Liu { 192547c09d6aSSong Liu .name = "llc_misses", 192647c09d6aSSong Liu .attr = { 192747c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 192847c09d6aSSong Liu .config = 192947c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 193047c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 193147c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 193247c09d6aSSong Liu .exclude_user = 1 193347c09d6aSSong Liu }, 193447c09d6aSSong Liu .ratio_metric = 2, 193547c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 193647c09d6aSSong Liu .ratio_mul = 1e6, 193747c09d6aSSong Liu }, 1938450d060eSYonghong Song { 1939450d060eSYonghong Song .name = "itlb_misses", 1940450d060eSYonghong Song .attr = { 1941450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1942450d060eSYonghong Song .config = 1943450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 1944450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1945450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1946450d060eSYonghong Song .exclude_user = 1 1947450d060eSYonghong Song }, 1948450d060eSYonghong Song .ratio_metric = 2, 1949450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 1950450d060eSYonghong Song .ratio_mul = 1e6, 1951450d060eSYonghong Song }, 1952450d060eSYonghong Song { 1953450d060eSYonghong Song .name = "dtlb_misses", 1954450d060eSYonghong Song .attr = { 1955450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1956450d060eSYonghong Song .config = 1957450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 1958450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1959450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1960450d060eSYonghong Song .exclude_user = 1 1961450d060eSYonghong Song }, 1962450d060eSYonghong Song .ratio_metric = 2, 1963450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 1964450d060eSYonghong Song .ratio_mul = 1e6, 1965450d060eSYonghong Song }, 196647c09d6aSSong Liu }; 196747c09d6aSSong Liu 196847c09d6aSSong Liu static __u64 profile_total_count; 196947c09d6aSSong Liu 197047c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 197147c09d6aSSong Liu 197247c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 197347c09d6aSSong Liu { 197447c09d6aSSong Liu unsigned int metric_cnt; 197547c09d6aSSong Liu int selected_cnt = 0; 197647c09d6aSSong Liu unsigned int i; 197747c09d6aSSong Liu 197847c09d6aSSong Liu metric_cnt = sizeof(metrics) / sizeof(struct profile_metric); 197947c09d6aSSong Liu 198047c09d6aSSong Liu while (argc > 0) { 198147c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 198247c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 198347c09d6aSSong Liu if (!metrics[i].selected) 198447c09d6aSSong Liu selected_cnt++; 198547c09d6aSSong Liu metrics[i].selected = true; 198647c09d6aSSong Liu break; 198747c09d6aSSong Liu } 198847c09d6aSSong Liu } 198947c09d6aSSong Liu if (i == metric_cnt) { 199047c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 199147c09d6aSSong Liu return -1; 199247c09d6aSSong Liu } 199347c09d6aSSong Liu NEXT_ARG(); 199447c09d6aSSong Liu } 199547c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 199647c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 199747c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 199847c09d6aSSong Liu return -1; 199947c09d6aSSong Liu } 200047c09d6aSSong Liu return selected_cnt; 200147c09d6aSSong Liu } 200247c09d6aSSong Liu 200347c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 200447c09d6aSSong Liu { 200547c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 200647c09d6aSSong Liu int reading_map_fd, count_map_fd; 200747c09d6aSSong Liu __u64 counts[num_cpu]; 200847c09d6aSSong Liu __u32 key = 0; 200947c09d6aSSong Liu int err; 201047c09d6aSSong Liu 201147c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 201247c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 201347c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 201447c09d6aSSong Liu p_err("failed to get fd for map"); 201547c09d6aSSong Liu return; 201647c09d6aSSong Liu } 201747c09d6aSSong Liu 201847c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 201947c09d6aSSong Liu if (err) { 202047c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 202147c09d6aSSong Liu return; 202247c09d6aSSong Liu } 202347c09d6aSSong Liu 202447c09d6aSSong Liu profile_total_count = 0; 202547c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 202647c09d6aSSong Liu profile_total_count += counts[cpu]; 202747c09d6aSSong Liu 202847c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 202947c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 203047c09d6aSSong Liu 203147c09d6aSSong Liu if (!metrics[m].selected) 203247c09d6aSSong Liu continue; 203347c09d6aSSong Liu 203447c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 203547c09d6aSSong Liu if (err) { 203647c09d6aSSong Liu p_err("failed to read reading_map: %s", 203747c09d6aSSong Liu strerror(errno)); 203847c09d6aSSong Liu return; 203947c09d6aSSong Liu } 204047c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 204147c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 204247c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 204347c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 204447c09d6aSSong Liu } 204547c09d6aSSong Liu key++; 204647c09d6aSSong Liu } 204747c09d6aSSong Liu } 204847c09d6aSSong Liu 204947c09d6aSSong Liu static void profile_print_readings_json(void) 205047c09d6aSSong Liu { 205147c09d6aSSong Liu __u32 m; 205247c09d6aSSong Liu 205347c09d6aSSong Liu jsonw_start_array(json_wtr); 205447c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 205547c09d6aSSong Liu if (!metrics[m].selected) 205647c09d6aSSong Liu continue; 205747c09d6aSSong Liu jsonw_start_object(json_wtr); 205847c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 205947c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 206047c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 206147c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 206247c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 206347c09d6aSSong Liu 206447c09d6aSSong Liu jsonw_end_object(json_wtr); 206547c09d6aSSong Liu } 206647c09d6aSSong Liu jsonw_end_array(json_wtr); 206747c09d6aSSong Liu } 206847c09d6aSSong Liu 206947c09d6aSSong Liu static void profile_print_readings_plain(void) 207047c09d6aSSong Liu { 207147c09d6aSSong Liu __u32 m; 207247c09d6aSSong Liu 207347c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 207447c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 207547c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 207647c09d6aSSong Liu int r; 207747c09d6aSSong Liu 207847c09d6aSSong Liu if (!metrics[m].selected) 207947c09d6aSSong Liu continue; 208047c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 208147c09d6aSSong Liu 208247c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 208347c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 208447c09d6aSSong Liu metrics[r].val.counter > 0) { 208547c09d6aSSong Liu printf("# %8.2f %-30s", 208647c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 208747c09d6aSSong Liu metrics[r].val.counter, 208847c09d6aSSong Liu metrics[m].ratio_desc); 208947c09d6aSSong Liu } else { 209047c09d6aSSong Liu printf("%-41s", ""); 209147c09d6aSSong Liu } 209247c09d6aSSong Liu 209347c09d6aSSong Liu if (val->enabled > val->running) 209447c09d6aSSong Liu printf("(%4.2f%%)", 209547c09d6aSSong Liu val->running * 100.0 / val->enabled); 209647c09d6aSSong Liu printf("\n"); 209747c09d6aSSong Liu } 209847c09d6aSSong Liu } 209947c09d6aSSong Liu 210047c09d6aSSong Liu static void profile_print_readings(void) 210147c09d6aSSong Liu { 210247c09d6aSSong Liu if (json_output) 210347c09d6aSSong Liu profile_print_readings_json(); 210447c09d6aSSong Liu else 210547c09d6aSSong Liu profile_print_readings_plain(); 210647c09d6aSSong Liu } 210747c09d6aSSong Liu 210847c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 210947c09d6aSSong Liu { 2110c59765cfSDave Marchevsky struct bpf_func_info func_info; 2111c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2112c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 211347c09d6aSSong Liu const struct btf_type *t; 2114c59765cfSDave Marchevsky __u32 func_info_rec_size; 2115369e955bSQuentin Monnet struct btf *btf = NULL; 211647c09d6aSSong Liu char *name = NULL; 2117c59765cfSDave Marchevsky int err; 211847c09d6aSSong Liu 2119c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2120c59765cfSDave Marchevsky if (err) { 2121c59765cfSDave Marchevsky p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd); 2122c59765cfSDave Marchevsky goto out; 212347c09d6aSSong Liu } 212447c09d6aSSong Liu 2125c59765cfSDave Marchevsky if (info.btf_id == 0) { 212647c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 212747c09d6aSSong Liu goto out; 212847c09d6aSSong Liu } 212947c09d6aSSong Liu 2130c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2131c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 2132c59765cfSDave Marchevsky p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd); 2133c59765cfSDave Marchevsky goto out; 2134c59765cfSDave Marchevsky } 2135c59765cfSDave Marchevsky 2136c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2137c59765cfSDave Marchevsky info.nr_func_info = 1; 2138c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2139c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2140c59765cfSDave Marchevsky 2141c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2142c59765cfSDave Marchevsky if (err) { 2143c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2144c59765cfSDave Marchevsky goto out; 2145c59765cfSDave Marchevsky } 2146c59765cfSDave Marchevsky 2147c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 214886f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 214986f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 215086f4b7f2SQuentin Monnet goto out; 215186f4b7f2SQuentin Monnet } 215286f4b7f2SQuentin Monnet 2153c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 215447c09d6aSSong Liu if (!t) { 215547c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2156c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 215747c09d6aSSong Liu goto out; 215847c09d6aSSong Liu } 215947c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 216047c09d6aSSong Liu out: 2161369e955bSQuentin Monnet btf__free(btf); 216247c09d6aSSong Liu return name; 216347c09d6aSSong Liu } 216447c09d6aSSong Liu 216547c09d6aSSong Liu static struct profiler_bpf *profile_obj; 216647c09d6aSSong Liu static int profile_tgt_fd = -1; 216747c09d6aSSong Liu static char *profile_tgt_name; 216847c09d6aSSong Liu static int *profile_perf_events; 216947c09d6aSSong Liu static int profile_perf_event_cnt; 217047c09d6aSSong Liu 217147c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 217247c09d6aSSong Liu { 217347c09d6aSSong Liu int i; 217447c09d6aSSong Liu 217547c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 217647c09d6aSSong Liu close(profile_perf_events[i]); 217747c09d6aSSong Liu 217847c09d6aSSong Liu free(profile_perf_events); 217947c09d6aSSong Liu profile_perf_event_cnt = 0; 218047c09d6aSSong Liu } 218147c09d6aSSong Liu 218247c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 218347c09d6aSSong Liu { 218447c09d6aSSong Liu unsigned int cpu, m; 218547c09d6aSSong Liu int map_fd, pmu_fd; 218647c09d6aSSong Liu 218747c09d6aSSong Liu profile_perf_events = calloc( 218847c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 218947c09d6aSSong Liu if (!profile_perf_events) { 219047c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 219147c09d6aSSong Liu strerror(errno)); 219247c09d6aSSong Liu return -1; 219347c09d6aSSong Liu } 219447c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 219547c09d6aSSong Liu if (map_fd < 0) { 219647c09d6aSSong Liu p_err("failed to get fd for events map"); 219747c09d6aSSong Liu return -1; 219847c09d6aSSong Liu } 219947c09d6aSSong Liu 220047c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 220147c09d6aSSong Liu if (!metrics[m].selected) 220247c09d6aSSong Liu continue; 220347c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 220447c09d6aSSong Liu pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 220547c09d6aSSong Liu -1/*pid*/, cpu, -1/*group_fd*/, 0); 220647c09d6aSSong Liu if (pmu_fd < 0 || 220747c09d6aSSong Liu bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 220847c09d6aSSong Liu &pmu_fd, BPF_ANY) || 220947c09d6aSSong Liu ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 221047c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 221147c09d6aSSong Liu metrics[m].name, cpu); 221247c09d6aSSong Liu return -1; 221347c09d6aSSong Liu } 221447c09d6aSSong Liu profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 221547c09d6aSSong Liu } 221647c09d6aSSong Liu } 221747c09d6aSSong Liu return 0; 221847c09d6aSSong Liu } 221947c09d6aSSong Liu 222047c09d6aSSong Liu static void profile_print_and_cleanup(void) 222147c09d6aSSong Liu { 222247c09d6aSSong Liu profile_close_perf_events(profile_obj); 222347c09d6aSSong Liu profile_read_values(profile_obj); 222447c09d6aSSong Liu profile_print_readings(); 222547c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 222647c09d6aSSong Liu 222747c09d6aSSong Liu close(profile_tgt_fd); 222847c09d6aSSong Liu free(profile_tgt_name); 222947c09d6aSSong Liu } 223047c09d6aSSong Liu 223147c09d6aSSong Liu static void int_exit(int signo) 223247c09d6aSSong Liu { 223347c09d6aSSong Liu profile_print_and_cleanup(); 223447c09d6aSSong Liu exit(0); 223547c09d6aSSong Liu } 223647c09d6aSSong Liu 223747c09d6aSSong Liu static int do_profile(int argc, char **argv) 223847c09d6aSSong Liu { 223947c09d6aSSong Liu int num_metric, num_cpu, err = -1; 224047c09d6aSSong Liu struct bpf_program *prog; 224147c09d6aSSong Liu unsigned long duration; 224247c09d6aSSong Liu char *endptr; 224347c09d6aSSong Liu 224447c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 224547c09d6aSSong Liu if (!REQ_ARGS(3)) 224647c09d6aSSong Liu return -EINVAL; 224747c09d6aSSong Liu 224847c09d6aSSong Liu /* parse target fd */ 224947c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 225047c09d6aSSong Liu if (profile_tgt_fd < 0) { 225147c09d6aSSong Liu p_err("failed to parse fd"); 225247c09d6aSSong Liu return -1; 225347c09d6aSSong Liu } 225447c09d6aSSong Liu 225547c09d6aSSong Liu /* parse profiling optional duration */ 225647c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 225747c09d6aSSong Liu NEXT_ARG(); 225847c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 225947c09d6aSSong Liu if (*endptr) 226047c09d6aSSong Liu usage(); 226147c09d6aSSong Liu NEXT_ARG(); 226247c09d6aSSong Liu } else { 226347c09d6aSSong Liu duration = UINT_MAX; 226447c09d6aSSong Liu } 226547c09d6aSSong Liu 226647c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 226747c09d6aSSong Liu if (num_metric <= 0) 226847c09d6aSSong Liu goto out; 226947c09d6aSSong Liu 227047c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 227147c09d6aSSong Liu if (num_cpu <= 0) { 227247c09d6aSSong Liu p_err("failed to identify number of CPUs"); 227347c09d6aSSong Liu goto out; 227447c09d6aSSong Liu } 227547c09d6aSSong Liu 227647c09d6aSSong Liu profile_obj = profiler_bpf__open(); 227747c09d6aSSong Liu if (!profile_obj) { 227847c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 227947c09d6aSSong Liu goto out; 228047c09d6aSSong Liu } 228147c09d6aSSong Liu 228247c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 228347c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 228447c09d6aSSong Liu 228547c09d6aSSong Liu /* adjust map sizes */ 228647c09d6aSSong Liu bpf_map__resize(profile_obj->maps.events, num_metric * num_cpu); 228747c09d6aSSong Liu bpf_map__resize(profile_obj->maps.fentry_readings, num_metric); 228847c09d6aSSong Liu bpf_map__resize(profile_obj->maps.accum_readings, num_metric); 228947c09d6aSSong Liu bpf_map__resize(profile_obj->maps.counts, 1); 229047c09d6aSSong Liu 229147c09d6aSSong Liu /* change target name */ 229247c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 229347c09d6aSSong Liu if (!profile_tgt_name) 229447c09d6aSSong Liu goto out; 229547c09d6aSSong Liu 229647c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 229747c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 229847c09d6aSSong Liu profile_tgt_name); 229947c09d6aSSong Liu if (err) { 230047c09d6aSSong Liu p_err("failed to set attach target\n"); 230147c09d6aSSong Liu goto out; 230247c09d6aSSong Liu } 230347c09d6aSSong Liu } 230447c09d6aSSong Liu 230547c09d6aSSong Liu set_max_rlimit(); 230647c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 230747c09d6aSSong Liu if (err) { 230847c09d6aSSong Liu p_err("failed to load profile_obj"); 230947c09d6aSSong Liu goto out; 231047c09d6aSSong Liu } 231147c09d6aSSong Liu 231247c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 231347c09d6aSSong Liu if (err) 231447c09d6aSSong Liu goto out; 231547c09d6aSSong Liu 231647c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 231747c09d6aSSong Liu if (err) { 231847c09d6aSSong Liu p_err("failed to attach profile_obj"); 231947c09d6aSSong Liu goto out; 232047c09d6aSSong Liu } 232147c09d6aSSong Liu signal(SIGINT, int_exit); 232247c09d6aSSong Liu 232347c09d6aSSong Liu sleep(duration); 232447c09d6aSSong Liu profile_print_and_cleanup(); 232547c09d6aSSong Liu return 0; 232647c09d6aSSong Liu 232747c09d6aSSong Liu out: 232847c09d6aSSong Liu profile_close_perf_events(profile_obj); 232947c09d6aSSong Liu if (profile_obj) 233047c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 233147c09d6aSSong Liu close(profile_tgt_fd); 233247c09d6aSSong Liu free(profile_tgt_name); 233347c09d6aSSong Liu return err; 233447c09d6aSSong Liu } 233547c09d6aSSong Liu 233647c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 233747c09d6aSSong Liu 233871bb428fSJakub Kicinski static int do_help(int argc, char **argv) 233971bb428fSJakub Kicinski { 2340004b45c0SQuentin Monnet if (json_output) { 2341004b45c0SQuentin Monnet jsonw_null(json_wtr); 2342004b45c0SQuentin Monnet return 0; 2343004b45c0SQuentin Monnet } 2344004b45c0SQuentin Monnet 234571bb428fSJakub Kicinski fprintf(stderr, 234690040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 234790040351SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 234890040351SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | opcodes | linum }]\n" 234990040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 235090040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 235177380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 23523767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 23533767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 235490040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 235590040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 235690040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2357ba95c745SQuentin Monnet " data_in FILE \\\n" 2358ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2359ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2360ba95c745SQuentin Monnet " [repeat N]\n" 236190040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 236290040351SQuentin Monnet " %1$s %2$s tracelog\n" 236390040351SQuentin Monnet " %1$s %2$s help\n" 236471bb428fSJakub Kicinski "\n" 23653ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 236671bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 236749f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 236849f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 236949f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 237049f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2371f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 237249f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 237349f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 237405ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 237505ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 237605ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2377a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 237893a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 2379b544342eSQuentin Monnet " ATTACH_TYPE := { msg_verdict | skb_verdict | stream_verdict |\n" 2380b544342eSQuentin Monnet " stream_parser | flow_dissector }\n" 2381450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2382c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 23838cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 23848cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 238571bb428fSJakub Kicinski "", 238690040351SQuentin Monnet bin_name, argv[-2]); 238771bb428fSJakub Kicinski 238871bb428fSJakub Kicinski return 0; 238971bb428fSJakub Kicinski } 239071bb428fSJakub Kicinski 239171bb428fSJakub Kicinski static const struct cmd cmds[] = { 239271bb428fSJakub Kicinski { "show", do_show }, 23936ebe6dbdSJakub Kicinski { "list", do_show }, 23949f606179SQuentin Monnet { "help", do_help }, 239571bb428fSJakub Kicinski { "dump", do_dump }, 239671bb428fSJakub Kicinski { "pin", do_pin }, 239749a086c2SRoman Gushchin { "load", do_load }, 239877380998SStanislav Fomichev { "loadall", do_loadall }, 2399b7d3826cSJohn Fastabend { "attach", do_attach }, 2400b7d3826cSJohn Fastabend { "detach", do_detach }, 240130da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2402ba95c745SQuentin Monnet { "run", do_run }, 240347c09d6aSSong Liu { "profile", do_profile }, 240471bb428fSJakub Kicinski { 0 } 240571bb428fSJakub Kicinski }; 240671bb428fSJakub Kicinski 240771bb428fSJakub Kicinski int do_prog(int argc, char **argv) 240871bb428fSJakub Kicinski { 240971bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 241071bb428fSJakub Kicinski } 2411