102ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 202ff58dcSJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 371bb428fSJakub Kicinski 43ff5a4dcSJakub Kicinski #define _GNU_SOURCE 571bb428fSJakub Kicinski #include <errno.h> 671bb428fSJakub Kicinski #include <fcntl.h> 747c09d6aSSong Liu #include <signal.h> 8c9c35995SJakub Kicinski #include <stdarg.h> 971bb428fSJakub Kicinski #include <stdio.h> 1071bb428fSJakub Kicinski #include <stdlib.h> 1171bb428fSJakub Kicinski #include <string.h> 1271bb428fSJakub Kicinski #include <time.h> 1371bb428fSJakub Kicinski #include <unistd.h> 14ba6dd679SJakub Kicinski #include <net/if.h> 1547c09d6aSSong Liu #include <sys/ioctl.h> 1671bb428fSJakub Kicinski #include <sys/types.h> 1771bb428fSJakub Kicinski #include <sys/stat.h> 1847c09d6aSSong Liu #include <sys/syscall.h> 19d510296dSAlexei Starovoitov #include <dirent.h> 2071bb428fSJakub Kicinski 21c8406848SJakub Kicinski #include <linux/err.h> 2247c09d6aSSong Liu #include <linux/perf_event.h> 23ba95c745SQuentin Monnet #include <linux/sizes.h> 24c8406848SJakub Kicinski 25229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h> 26229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h> 278f184732SQuentin Monnet #include <bpf/hashmap.h> 28229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h> 29a19df713SMauricio Vásquez #include <bpf/libbpf_internal.h> 30d510296dSAlexei Starovoitov #include <bpf/skel_internal.h> 3171bb428fSJakub Kicinski 32b6c1cedbSJiong Wang #include "cfg.h" 3371bb428fSJakub Kicinski #include "main.h" 3473bb5b4fSJiong Wang #include "xlated_dumper.h" 3571bb428fSJakub Kicinski 36aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX "bpf_metadata_" 37aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1) 38aff52e68SYiFei Zhu 39ec202509SPaul Chaignon enum dump_mode { 40ec202509SPaul Chaignon DUMP_JITED, 41ec202509SPaul Chaignon DUMP_XLATED, 42ec202509SPaul Chaignon }; 43ec202509SPaul Chaignon 44b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 45b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 46b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 47a7ba4558SCong Wang [BPF_SK_SKB_VERDICT] = "skb_verdict", 48b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 49092f0892SStanislav Fomichev [BPF_FLOW_DISSECTOR] = "flow_dissector", 50b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 51b7d3826cSJohn Fastabend }; 52b7d3826cSJohn Fastabend 538f184732SQuentin Monnet static struct hashmap *prog_table; 5446241271SQuentin Monnet 55c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 56b7d3826cSJohn Fastabend { 57b7d3826cSJohn Fastabend enum bpf_attach_type type; 58b7d3826cSJohn Fastabend 59b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 60b7d3826cSJohn Fastabend if (attach_type_strings[type] && 61b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 62b7d3826cSJohn Fastabend return type; 63b7d3826cSJohn Fastabend } 64b7d3826cSJohn Fastabend 65b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 66b7d3826cSJohn Fastabend } 67b7d3826cSJohn Fastabend 68c59765cfSDave Marchevsky static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 69c59765cfSDave Marchevsky void **info_data, size_t *const info_data_sz) 70c59765cfSDave Marchevsky { 71c59765cfSDave Marchevsky struct bpf_prog_info holder = {}; 72c59765cfSDave Marchevsky size_t needed = 0; 73c59765cfSDave Marchevsky void *ptr; 74c59765cfSDave Marchevsky 75c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 76c59765cfSDave Marchevsky holder.jited_prog_len = info->jited_prog_len; 77c59765cfSDave Marchevsky needed += info->jited_prog_len; 78c59765cfSDave Marchevsky } else { 79c59765cfSDave Marchevsky holder.xlated_prog_len = info->xlated_prog_len; 80c59765cfSDave Marchevsky needed += info->xlated_prog_len; 81c59765cfSDave Marchevsky } 82c59765cfSDave Marchevsky 83c59765cfSDave Marchevsky holder.nr_jited_ksyms = info->nr_jited_ksyms; 84c59765cfSDave Marchevsky needed += info->nr_jited_ksyms * sizeof(__u64); 85c59765cfSDave Marchevsky 86c59765cfSDave Marchevsky holder.nr_jited_func_lens = info->nr_jited_func_lens; 87c59765cfSDave Marchevsky needed += info->nr_jited_func_lens * sizeof(__u32); 88c59765cfSDave Marchevsky 89c59765cfSDave Marchevsky holder.nr_func_info = info->nr_func_info; 90c59765cfSDave Marchevsky holder.func_info_rec_size = info->func_info_rec_size; 91c59765cfSDave Marchevsky needed += info->nr_func_info * info->func_info_rec_size; 92c59765cfSDave Marchevsky 93c59765cfSDave Marchevsky holder.nr_line_info = info->nr_line_info; 94c59765cfSDave Marchevsky holder.line_info_rec_size = info->line_info_rec_size; 95c59765cfSDave Marchevsky needed += info->nr_line_info * info->line_info_rec_size; 96c59765cfSDave Marchevsky 97c59765cfSDave Marchevsky holder.nr_jited_line_info = info->nr_jited_line_info; 98c59765cfSDave Marchevsky holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 99c59765cfSDave Marchevsky needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 100c59765cfSDave Marchevsky 101c59765cfSDave Marchevsky if (needed > *info_data_sz) { 102c59765cfSDave Marchevsky ptr = realloc(*info_data, needed); 103c59765cfSDave Marchevsky if (!ptr) 104c59765cfSDave Marchevsky return -1; 105c59765cfSDave Marchevsky 106c59765cfSDave Marchevsky *info_data = ptr; 107c59765cfSDave Marchevsky *info_data_sz = needed; 108c59765cfSDave Marchevsky } 109c59765cfSDave Marchevsky ptr = *info_data; 110c59765cfSDave Marchevsky 111c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 112c59765cfSDave Marchevsky holder.jited_prog_insns = ptr_to_u64(ptr); 113c59765cfSDave Marchevsky ptr += holder.jited_prog_len; 114c59765cfSDave Marchevsky } else { 115c59765cfSDave Marchevsky holder.xlated_prog_insns = ptr_to_u64(ptr); 116c59765cfSDave Marchevsky ptr += holder.xlated_prog_len; 117c59765cfSDave Marchevsky } 118c59765cfSDave Marchevsky 119c59765cfSDave Marchevsky holder.jited_ksyms = ptr_to_u64(ptr); 120c59765cfSDave Marchevsky ptr += holder.nr_jited_ksyms * sizeof(__u64); 121c59765cfSDave Marchevsky 122c59765cfSDave Marchevsky holder.jited_func_lens = ptr_to_u64(ptr); 123c59765cfSDave Marchevsky ptr += holder.nr_jited_func_lens * sizeof(__u32); 124c59765cfSDave Marchevsky 125c59765cfSDave Marchevsky holder.func_info = ptr_to_u64(ptr); 126c59765cfSDave Marchevsky ptr += holder.nr_func_info * holder.func_info_rec_size; 127c59765cfSDave Marchevsky 128c59765cfSDave Marchevsky holder.line_info = ptr_to_u64(ptr); 129c59765cfSDave Marchevsky ptr += holder.nr_line_info * holder.line_info_rec_size; 130c59765cfSDave Marchevsky 131c59765cfSDave Marchevsky holder.jited_line_info = ptr_to_u64(ptr); 132c59765cfSDave Marchevsky ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 133c59765cfSDave Marchevsky 134c59765cfSDave Marchevsky *info = holder; 135c59765cfSDave Marchevsky return 0; 136c59765cfSDave Marchevsky } 137c59765cfSDave Marchevsky 13871bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 13971bb428fSJakub Kicinski { 14071bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 14171bb428fSJakub Kicinski time_t wallclock_secs; 14271bb428fSJakub Kicinski struct tm load_tm; 14371bb428fSJakub Kicinski 14471bb428fSJakub Kicinski buf[--size] = '\0'; 14571bb428fSJakub Kicinski 14671bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 14771bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 14871bb428fSJakub Kicinski perror("Can't read clocks"); 14971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 15071bb428fSJakub Kicinski return; 15171bb428fSJakub Kicinski } 15271bb428fSJakub Kicinski 15371bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 15407480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 15507480cbcSJakub Kicinski 1000000000; 15607480cbcSJakub Kicinski 15771bb428fSJakub Kicinski 15871bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 15971bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 16071bb428fSJakub Kicinski return; 16171bb428fSJakub Kicinski } 16271bb428fSJakub Kicinski 163a3fe1f6fSQuentin Monnet if (json_output) 164a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 165a3fe1f6fSQuentin Monnet else 166a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 16771bb428fSJakub Kicinski } 16871bb428fSJakub Kicinski 1696e7e034eSQuentin Monnet static void show_prog_maps(int fd, __u32 num_maps) 17071bb428fSJakub Kicinski { 17171bb428fSJakub Kicinski struct bpf_prog_info info = {}; 17271bb428fSJakub Kicinski __u32 len = sizeof(info); 17371bb428fSJakub Kicinski __u32 map_ids[num_maps]; 17471bb428fSJakub Kicinski unsigned int i; 17571bb428fSJakub Kicinski int err; 17671bb428fSJakub Kicinski 17771bb428fSJakub Kicinski info.nr_map_ids = num_maps; 17871bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 17971bb428fSJakub Kicinski 18071bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 18171bb428fSJakub Kicinski if (err || !info.nr_map_ids) 18271bb428fSJakub Kicinski return; 18371bb428fSJakub Kicinski 184743cc665SQuentin Monnet if (json_output) { 185743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 186743cc665SQuentin Monnet jsonw_start_array(json_wtr); 187743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 188743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 189743cc665SQuentin Monnet jsonw_end_array(json_wtr); 190743cc665SQuentin Monnet } else { 19171bb428fSJakub Kicinski printf(" map_ids "); 19271bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 19371bb428fSJakub Kicinski printf("%u%s", map_ids[i], 19471bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 19571bb428fSJakub Kicinski } 19671bb428fSJakub Kicinski } 19771bb428fSJakub Kicinski 198aff52e68SYiFei Zhu static void *find_metadata(int prog_fd, struct bpf_map_info *map_info) 199aff52e68SYiFei Zhu { 200aff52e68SYiFei Zhu struct bpf_prog_info prog_info; 201aff52e68SYiFei Zhu __u32 prog_info_len; 202aff52e68SYiFei Zhu __u32 map_info_len; 203aff52e68SYiFei Zhu void *value = NULL; 204aff52e68SYiFei Zhu __u32 *map_ids; 205aff52e68SYiFei Zhu int nr_maps; 206aff52e68SYiFei Zhu int key = 0; 207aff52e68SYiFei Zhu int map_fd; 208aff52e68SYiFei Zhu int ret; 209aff52e68SYiFei Zhu __u32 i; 210aff52e68SYiFei Zhu 211aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 212aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 213aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 214aff52e68SYiFei Zhu if (ret) 215aff52e68SYiFei Zhu return NULL; 216aff52e68SYiFei Zhu 217aff52e68SYiFei Zhu if (!prog_info.nr_map_ids) 218aff52e68SYiFei Zhu return NULL; 219aff52e68SYiFei Zhu 220aff52e68SYiFei Zhu map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); 221aff52e68SYiFei Zhu if (!map_ids) 222aff52e68SYiFei Zhu return NULL; 223aff52e68SYiFei Zhu 224aff52e68SYiFei Zhu nr_maps = prog_info.nr_map_ids; 225aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 226aff52e68SYiFei Zhu prog_info.nr_map_ids = nr_maps; 227aff52e68SYiFei Zhu prog_info.map_ids = ptr_to_u64(map_ids); 228aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 229aff52e68SYiFei Zhu 230aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 231aff52e68SYiFei Zhu if (ret) 232aff52e68SYiFei Zhu goto free_map_ids; 233aff52e68SYiFei Zhu 234aff52e68SYiFei Zhu for (i = 0; i < prog_info.nr_map_ids; i++) { 235aff52e68SYiFei Zhu map_fd = bpf_map_get_fd_by_id(map_ids[i]); 236aff52e68SYiFei Zhu if (map_fd < 0) 237aff52e68SYiFei Zhu goto free_map_ids; 238aff52e68SYiFei Zhu 239aff52e68SYiFei Zhu memset(map_info, 0, sizeof(*map_info)); 240aff52e68SYiFei Zhu map_info_len = sizeof(*map_info); 241aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(map_fd, map_info, &map_info_len); 242aff52e68SYiFei Zhu if (ret < 0) { 243aff52e68SYiFei Zhu close(map_fd); 244aff52e68SYiFei Zhu goto free_map_ids; 245aff52e68SYiFei Zhu } 246aff52e68SYiFei Zhu 247aff52e68SYiFei Zhu if (map_info->type != BPF_MAP_TYPE_ARRAY || 248aff52e68SYiFei Zhu map_info->key_size != sizeof(int) || 249aff52e68SYiFei Zhu map_info->max_entries != 1 || 250aff52e68SYiFei Zhu !map_info->btf_value_type_id || 251aff52e68SYiFei Zhu !strstr(map_info->name, ".rodata")) { 252aff52e68SYiFei Zhu close(map_fd); 253aff52e68SYiFei Zhu continue; 254aff52e68SYiFei Zhu } 255aff52e68SYiFei Zhu 256aff52e68SYiFei Zhu value = malloc(map_info->value_size); 257aff52e68SYiFei Zhu if (!value) { 258aff52e68SYiFei Zhu close(map_fd); 259aff52e68SYiFei Zhu goto free_map_ids; 260aff52e68SYiFei Zhu } 261aff52e68SYiFei Zhu 262aff52e68SYiFei Zhu if (bpf_map_lookup_elem(map_fd, &key, value)) { 263aff52e68SYiFei Zhu close(map_fd); 264aff52e68SYiFei Zhu free(value); 265aff52e68SYiFei Zhu value = NULL; 266aff52e68SYiFei Zhu goto free_map_ids; 267aff52e68SYiFei Zhu } 268aff52e68SYiFei Zhu 269aff52e68SYiFei Zhu close(map_fd); 270aff52e68SYiFei Zhu break; 271aff52e68SYiFei Zhu } 272aff52e68SYiFei Zhu 273aff52e68SYiFei Zhu free_map_ids: 274aff52e68SYiFei Zhu free(map_ids); 275aff52e68SYiFei Zhu return value; 276aff52e68SYiFei Zhu } 277aff52e68SYiFei Zhu 278aff52e68SYiFei Zhu static bool has_metadata_prefix(const char *s) 279aff52e68SYiFei Zhu { 280aff52e68SYiFei Zhu return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0; 281aff52e68SYiFei Zhu } 282aff52e68SYiFei Zhu 283aff52e68SYiFei Zhu static void show_prog_metadata(int fd, __u32 num_maps) 284aff52e68SYiFei Zhu { 285aff52e68SYiFei Zhu const struct btf_type *t_datasec, *t_var; 286aff52e68SYiFei Zhu struct bpf_map_info map_info; 287aff52e68SYiFei Zhu struct btf_var_secinfo *vsi; 288aff52e68SYiFei Zhu bool printed_header = false; 289aff52e68SYiFei Zhu unsigned int i, vlen; 290aff52e68SYiFei Zhu void *value = NULL; 291aff52e68SYiFei Zhu const char *name; 29286f4b7f2SQuentin Monnet struct btf *btf; 293aff52e68SYiFei Zhu int err; 294aff52e68SYiFei Zhu 295aff52e68SYiFei Zhu if (!num_maps) 296aff52e68SYiFei Zhu return; 297aff52e68SYiFei Zhu 298aff52e68SYiFei Zhu memset(&map_info, 0, sizeof(map_info)); 299aff52e68SYiFei Zhu value = find_metadata(fd, &map_info); 300aff52e68SYiFei Zhu if (!value) 301aff52e68SYiFei Zhu return; 302aff52e68SYiFei Zhu 30386f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(map_info.btf_id); 30486f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) 305aff52e68SYiFei Zhu goto out_free; 306aff52e68SYiFei Zhu 307aff52e68SYiFei Zhu t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); 308aff52e68SYiFei Zhu if (!btf_is_datasec(t_datasec)) 309aff52e68SYiFei Zhu goto out_free; 310aff52e68SYiFei Zhu 311aff52e68SYiFei Zhu vlen = btf_vlen(t_datasec); 312aff52e68SYiFei Zhu vsi = btf_var_secinfos(t_datasec); 313aff52e68SYiFei Zhu 314aff52e68SYiFei Zhu /* We don't proceed to check the kinds of the elements of the DATASEC. 315aff52e68SYiFei Zhu * The verifier enforces them to be BTF_KIND_VAR. 316aff52e68SYiFei Zhu */ 317aff52e68SYiFei Zhu 318aff52e68SYiFei Zhu if (json_output) { 319aff52e68SYiFei Zhu struct btf_dumper d = { 320aff52e68SYiFei Zhu .btf = btf, 321aff52e68SYiFei Zhu .jw = json_wtr, 322aff52e68SYiFei Zhu .is_plain_text = false, 323aff52e68SYiFei Zhu }; 324aff52e68SYiFei Zhu 325aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 326aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 327aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 328aff52e68SYiFei Zhu 329aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 330aff52e68SYiFei Zhu continue; 331aff52e68SYiFei Zhu 332aff52e68SYiFei Zhu if (!printed_header) { 333aff52e68SYiFei Zhu jsonw_name(json_wtr, "metadata"); 334aff52e68SYiFei Zhu jsonw_start_object(json_wtr); 335aff52e68SYiFei Zhu printed_header = true; 336aff52e68SYiFei Zhu } 337aff52e68SYiFei Zhu 338aff52e68SYiFei Zhu jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); 339aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 340aff52e68SYiFei Zhu if (err) { 341aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 342aff52e68SYiFei Zhu break; 343aff52e68SYiFei Zhu } 344aff52e68SYiFei Zhu } 345aff52e68SYiFei Zhu if (printed_header) 346aff52e68SYiFei Zhu jsonw_end_object(json_wtr); 347aff52e68SYiFei Zhu } else { 348e89ef634SQuentin Monnet json_writer_t *btf_wtr; 349aff52e68SYiFei Zhu struct btf_dumper d = { 350aff52e68SYiFei Zhu .btf = btf, 351aff52e68SYiFei Zhu .is_plain_text = true, 352aff52e68SYiFei Zhu }; 353aff52e68SYiFei Zhu 354aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 355aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 356aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 357aff52e68SYiFei Zhu 358aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 359aff52e68SYiFei Zhu continue; 360aff52e68SYiFei Zhu 361aff52e68SYiFei Zhu if (!printed_header) { 362aff52e68SYiFei Zhu printf("\tmetadata:"); 363e89ef634SQuentin Monnet 364e89ef634SQuentin Monnet btf_wtr = jsonw_new(stdout); 365e89ef634SQuentin Monnet if (!btf_wtr) { 366e89ef634SQuentin Monnet p_err("jsonw alloc failed"); 367e89ef634SQuentin Monnet goto out_free; 368e89ef634SQuentin Monnet } 369e89ef634SQuentin Monnet d.jw = btf_wtr, 370e89ef634SQuentin Monnet 371aff52e68SYiFei Zhu printed_header = true; 372aff52e68SYiFei Zhu } 373aff52e68SYiFei Zhu 374aff52e68SYiFei Zhu printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); 375aff52e68SYiFei Zhu 376aff52e68SYiFei Zhu jsonw_reset(btf_wtr); 377aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 378aff52e68SYiFei Zhu if (err) { 379aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 380aff52e68SYiFei Zhu break; 381aff52e68SYiFei Zhu } 382aff52e68SYiFei Zhu } 383aff52e68SYiFei Zhu if (printed_header) 384aff52e68SYiFei Zhu jsonw_destroy(&btf_wtr); 385aff52e68SYiFei Zhu } 386aff52e68SYiFei Zhu 387aff52e68SYiFei Zhu out_free: 388aff52e68SYiFei Zhu btf__free(btf); 389aff52e68SYiFei Zhu free(value); 390aff52e68SYiFei Zhu } 391aff52e68SYiFei Zhu 392b662000aSRaman Shukhau static void print_prog_header_json(struct bpf_prog_info *info, int fd) 393743cc665SQuentin Monnet { 394*b700eeb4SDaniel Müller const char *prog_type_str; 395b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 396b662000aSRaman Shukhau 397743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 398*b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 399*b700eeb4SDaniel Müller 400*b700eeb4SDaniel Müller if (prog_type_str) 401*b700eeb4SDaniel Müller jsonw_string_field(json_wtr, "type", prog_type_str); 40271bb428fSJakub Kicinski else 403743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 40471bb428fSJakub Kicinski 405b662000aSRaman Shukhau if (*info->name) { 406b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 407b662000aSRaman Shukhau jsonw_string_field(json_wtr, "name", prog_name); 408b662000aSRaman Shukhau } 40971bb428fSJakub Kicinski 410743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 411743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 412743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 413743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 41471bb428fSJakub Kicinski 4159b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 41688ad472bSAlexei Starovoitov if (info->run_time_ns) { 41788ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 41888ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 41988ad472bSAlexei Starovoitov } 4209ed9e9baSAlexei Starovoitov if (info->recursion_misses) 4219ed9e9baSAlexei Starovoitov jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 422ec202509SPaul Chaignon } 4239b984a20SJiri Olsa 424ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 425ec202509SPaul Chaignon { 426ec202509SPaul Chaignon char *memlock; 427ec202509SPaul Chaignon 428ec202509SPaul Chaignon jsonw_start_object(json_wtr); 429b662000aSRaman Shukhau print_prog_header_json(info, fd); 43052262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 43152262210SJakub Kicinski 432743cc665SQuentin Monnet if (info->load_time) { 43371bb428fSJakub Kicinski char buf[32]; 43471bb428fSJakub Kicinski 435743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 43671bb428fSJakub Kicinski 43771bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 438a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 439a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 440743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 44171bb428fSJakub Kicinski } 44271bb428fSJakub Kicinski 443743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 44471bb428fSJakub Kicinski 445743cc665SQuentin Monnet if (info->jited_prog_len) { 446743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 447743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 448743cc665SQuentin Monnet } else { 449743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 450743cc665SQuentin Monnet } 451743cc665SQuentin Monnet 452743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 453743cc665SQuentin Monnet if (memlock) 454357b3cc3SChris J Arges jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock)); 455743cc665SQuentin Monnet free(memlock); 456743cc665SQuentin Monnet 457743cc665SQuentin Monnet if (info->nr_map_ids) 458743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 459743cc665SQuentin Monnet 460569b0c77SPrashant Bhole if (info->btf_id) 461569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 462569b0c77SPrashant Bhole 4638f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 4648f184732SQuentin Monnet struct hashmap_entry *entry; 4654990f1f4SPrashant Bhole 4664990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 4674990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 4688f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 4698f184732SQuentin Monnet u32_as_hash_field(info->id)) 4708f184732SQuentin Monnet jsonw_string(json_wtr, entry->value); 4714990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 4724990f1f4SPrashant Bhole } 4734990f1f4SPrashant Bhole 474d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 475d53dee3fSAndrii Nakryiko 476aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 477aff52e68SYiFei Zhu 478743cc665SQuentin Monnet jsonw_end_object(json_wtr); 479743cc665SQuentin Monnet } 480743cc665SQuentin Monnet 481b662000aSRaman Shukhau static void print_prog_header_plain(struct bpf_prog_info *info, int fd) 482743cc665SQuentin Monnet { 483*b700eeb4SDaniel Müller const char *prog_type_str; 484b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 485b662000aSRaman Shukhau 486743cc665SQuentin Monnet printf("%u: ", info->id); 487*b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 488*b700eeb4SDaniel Müller if (prog_type_str) 489*b700eeb4SDaniel Müller printf("%s ", prog_type_str); 490743cc665SQuentin Monnet else 491743cc665SQuentin Monnet printf("type %u ", info->type); 492743cc665SQuentin Monnet 493b662000aSRaman Shukhau if (*info->name) { 494b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 495b662000aSRaman Shukhau printf("name %s ", prog_name); 496b662000aSRaman Shukhau } 497743cc665SQuentin Monnet 498743cc665SQuentin Monnet printf("tag "); 499743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 50052262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5019b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 50288ad472bSAlexei Starovoitov if (info->run_time_ns) 50388ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 50488ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5059ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5069ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 507743cc665SQuentin Monnet printf("\n"); 508ec202509SPaul Chaignon } 509ec202509SPaul Chaignon 510ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 511ec202509SPaul Chaignon { 512ec202509SPaul Chaignon char *memlock; 513ec202509SPaul Chaignon 514b662000aSRaman Shukhau print_prog_header_plain(info, fd); 515743cc665SQuentin Monnet 516743cc665SQuentin Monnet if (info->load_time) { 517743cc665SQuentin Monnet char buf[32]; 518743cc665SQuentin Monnet 519743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 520743cc665SQuentin Monnet 521743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 522743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 523743cc665SQuentin Monnet } 524743cc665SQuentin Monnet 525743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 526743cc665SQuentin Monnet 527743cc665SQuentin Monnet if (info->jited_prog_len) 528743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 52971bb428fSJakub Kicinski else 53071bb428fSJakub Kicinski printf(" not jited"); 53171bb428fSJakub Kicinski 53271bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 53371bb428fSJakub Kicinski if (memlock) 53471bb428fSJakub Kicinski printf(" memlock %sB", memlock); 53571bb428fSJakub Kicinski free(memlock); 53671bb428fSJakub Kicinski 537743cc665SQuentin Monnet if (info->nr_map_ids) 538743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 53971bb428fSJakub Kicinski 5408f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5418f184732SQuentin Monnet struct hashmap_entry *entry; 5424990f1f4SPrashant Bhole 5438f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 5448f184732SQuentin Monnet u32_as_hash_field(info->id)) 5458f184732SQuentin Monnet printf("\n\tpinned %s", (char *)entry->value); 5464990f1f4SPrashant Bhole } 5474990f1f4SPrashant Bhole 548569b0c77SPrashant Bhole if (info->btf_id) 549031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 550569b0c77SPrashant Bhole 551d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 552d53dee3fSAndrii Nakryiko 55371bb428fSJakub Kicinski printf("\n"); 554aff52e68SYiFei Zhu 555aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 556743cc665SQuentin Monnet } 557743cc665SQuentin Monnet 558743cc665SQuentin Monnet static int show_prog(int fd) 559743cc665SQuentin Monnet { 560743cc665SQuentin Monnet struct bpf_prog_info info = {}; 561743cc665SQuentin Monnet __u32 len = sizeof(info); 562743cc665SQuentin Monnet int err; 563743cc665SQuentin Monnet 564743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 565743cc665SQuentin Monnet if (err) { 5669a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 567743cc665SQuentin Monnet return -1; 568743cc665SQuentin Monnet } 569743cc665SQuentin Monnet 570743cc665SQuentin Monnet if (json_output) 571743cc665SQuentin Monnet print_prog_json(&info, fd); 572743cc665SQuentin Monnet else 573743cc665SQuentin Monnet print_prog_plain(&info, fd); 57471bb428fSJakub Kicinski 57571bb428fSJakub Kicinski return 0; 57671bb428fSJakub Kicinski } 57771bb428fSJakub Kicinski 578ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 579ec202509SPaul Chaignon { 580ec202509SPaul Chaignon int *fds = NULL; 581ec202509SPaul Chaignon int nb_fds, i; 582ec202509SPaul Chaignon int err = -1; 583ec202509SPaul Chaignon 584ec202509SPaul Chaignon fds = malloc(sizeof(int)); 585ec202509SPaul Chaignon if (!fds) { 586ec202509SPaul Chaignon p_err("mem alloc failed"); 587ec202509SPaul Chaignon return -1; 588ec202509SPaul Chaignon } 589ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 590ec202509SPaul Chaignon if (nb_fds < 1) 591ec202509SPaul Chaignon goto exit_free; 592ec202509SPaul Chaignon 593ec202509SPaul Chaignon if (json_output && nb_fds > 1) 594ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 595ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 596ec202509SPaul Chaignon err = show_prog(fds[i]); 597ec202509SPaul Chaignon if (err) { 598ec202509SPaul Chaignon for (; i < nb_fds; i++) 599ec202509SPaul Chaignon close(fds[i]); 600ec202509SPaul Chaignon break; 601ec202509SPaul Chaignon } 602ec202509SPaul Chaignon close(fds[i]); 603ec202509SPaul Chaignon } 604ec202509SPaul Chaignon if (json_output && nb_fds > 1) 605ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 606ec202509SPaul Chaignon 607ec202509SPaul Chaignon exit_free: 608ec202509SPaul Chaignon free(fds); 609ec202509SPaul Chaignon return err; 610ec202509SPaul Chaignon } 611ec202509SPaul Chaignon 61271bb428fSJakub Kicinski static int do_show(int argc, char **argv) 613743cc665SQuentin Monnet { 614743cc665SQuentin Monnet __u32 id = 0; 61571bb428fSJakub Kicinski int err; 61671bb428fSJakub Kicinski int fd; 61771bb428fSJakub Kicinski 61846241271SQuentin Monnet if (show_pinned) { 6198f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6208f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 621622a5b58SMauricio Vásquez if (IS_ERR(prog_table)) { 6228f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6238f184732SQuentin Monnet return -1; 6248f184732SQuentin Monnet } 6258f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 62646241271SQuentin Monnet } 627d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6284990f1f4SPrashant Bhole 629ec202509SPaul Chaignon if (argc == 2) 630ec202509SPaul Chaignon return do_show_subset(argc, argv); 63171bb428fSJakub Kicinski 63271bb428fSJakub Kicinski if (argc) 63371bb428fSJakub Kicinski return BAD_ARG(); 63471bb428fSJakub Kicinski 635743cc665SQuentin Monnet if (json_output) 636743cc665SQuentin Monnet jsonw_start_array(json_wtr); 63771bb428fSJakub Kicinski while (true) { 63871bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 63971bb428fSJakub Kicinski if (err) { 6401739c26dSQuentin Monnet if (errno == ENOENT) { 6411739c26dSQuentin Monnet err = 0; 64271bb428fSJakub Kicinski break; 6431739c26dSQuentin Monnet } 6449a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6459a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 646743cc665SQuentin Monnet err = -1; 647743cc665SQuentin Monnet break; 64871bb428fSJakub Kicinski } 64971bb428fSJakub Kicinski 65071bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 65171bb428fSJakub Kicinski if (fd < 0) { 6528207c6ddSJakub Kicinski if (errno == ENOENT) 6538207c6ddSJakub Kicinski continue; 6549a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 65571bb428fSJakub Kicinski id, strerror(errno)); 656743cc665SQuentin Monnet err = -1; 657743cc665SQuentin Monnet break; 65871bb428fSJakub Kicinski } 65971bb428fSJakub Kicinski 66071bb428fSJakub Kicinski err = show_prog(fd); 66171bb428fSJakub Kicinski close(fd); 66271bb428fSJakub Kicinski if (err) 663743cc665SQuentin Monnet break; 66471bb428fSJakub Kicinski } 66571bb428fSJakub Kicinski 666743cc665SQuentin Monnet if (json_output) 667743cc665SQuentin Monnet jsonw_end_array(json_wtr); 668743cc665SQuentin Monnet 669d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 670d53dee3fSAndrii Nakryiko 67146241271SQuentin Monnet if (show_pinned) 6728f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 67346241271SQuentin Monnet 674743cc665SQuentin Monnet return err; 67571bb428fSJakub Kicinski } 67671bb428fSJakub Kicinski 677ec202509SPaul Chaignon static int 678ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 679ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 68071bb428fSJakub Kicinski { 681b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 6823ddeac67SJakub Kicinski const char *disasm_opt = NULL; 6837105e828SDaniel Borkmann struct dump_data dd = {}; 684cae73f23SSong Liu void *func_info = NULL; 685254471e5SYonghong Song struct btf *btf = NULL; 686254471e5SYonghong Song char func_sig[1024]; 68771bb428fSJakub Kicinski unsigned char *buf; 688cae73f23SSong Liu __u32 member_len; 689ebbd7f64SQuentin Monnet int fd, err = -1; 69071bb428fSJakub Kicinski ssize_t n; 69171bb428fSJakub Kicinski 692cae73f23SSong Liu if (mode == DUMP_JITED) { 6935b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 6949a5ab8bfSQuentin Monnet p_info("no instructions returned"); 695ec202509SPaul Chaignon return -1; 696f84192eeSSandipan Das } 69709f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 698cae73f23SSong Liu member_len = info->jited_prog_len; 699cae73f23SSong Liu } else { /* DUMP_XLATED */ 700d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7017105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 702ec202509SPaul Chaignon return -1; 7037105e828SDaniel Borkmann } 70409f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 705cae73f23SSong Liu member_len = info->xlated_prog_len; 706cae73f23SSong Liu } 7077105e828SDaniel Borkmann 70886f4b7f2SQuentin Monnet if (info->btf_id) { 70986f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 71086f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 711254471e5SYonghong Song p_err("failed to get btf"); 712ec202509SPaul Chaignon return -1; 713254471e5SYonghong Song } 71486f4b7f2SQuentin Monnet } 715254471e5SYonghong Song 71609f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 717cae73f23SSong Liu 718cae73f23SSong Liu if (info->nr_line_info) { 719cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 720b053b439SMartin KaFai Lau if (!prog_linfo) 72110a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 722b053b439SMartin KaFai Lau } 723b053b439SMartin KaFai Lau 72471bb428fSJakub Kicinski if (filepath) { 72571bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 72671bb428fSJakub Kicinski if (fd < 0) { 7279a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 72871bb428fSJakub Kicinski strerror(errno)); 729ebbd7f64SQuentin Monnet goto exit_free; 73071bb428fSJakub Kicinski } 73171bb428fSJakub Kicinski 732cae73f23SSong Liu n = write(fd, buf, member_len); 73371bb428fSJakub Kicinski close(fd); 73409f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7359a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 73671bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 737ebbd7f64SQuentin Monnet goto exit_free; 73871bb428fSJakub Kicinski } 73952c84d36SQuentin Monnet 74052c84d36SQuentin Monnet if (json_output) 74152c84d36SQuentin Monnet jsonw_null(json_wtr); 742cae73f23SSong Liu } else if (mode == DUMP_JITED) { 743e6593596SJiong Wang const char *name = NULL; 744e6593596SJiong Wang 745cae73f23SSong Liu if (info->ifindex) { 746cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 747cae73f23SSong Liu info->netns_dev, 748cae73f23SSong Liu info->netns_ino, 7493ddeac67SJakub Kicinski &disasm_opt); 750e6593596SJiong Wang if (!name) 751ebbd7f64SQuentin Monnet goto exit_free; 752e6593596SJiong Wang } 753e6593596SJiong Wang 754cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 755f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 756254471e5SYonghong Song struct bpf_func_info *record; 757f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 758f7f62c71SSandipan Das unsigned char *img = buf; 759f7f62c71SSandipan Das __u64 *ksyms = NULL; 760f7f62c71SSandipan Das __u32 *lens; 761f7f62c71SSandipan Das __u32 i; 762cae73f23SSong Liu if (info->nr_jited_ksyms) { 763f7f62c71SSandipan Das kernel_syms_load(&dd); 76409f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 765f7f62c71SSandipan Das } 766f7f62c71SSandipan Das 767f7f62c71SSandipan Das if (json_output) 768f7f62c71SSandipan Das jsonw_start_array(json_wtr); 769f7f62c71SSandipan Das 77009f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 771cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 772f7f62c71SSandipan Das if (ksyms) { 773f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 774f7f62c71SSandipan Das if (sym) 775f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 776f7f62c71SSandipan Das else 777f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 778f7f62c71SSandipan Das } else { 779f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 780f7f62c71SSandipan Das } 781f7f62c71SSandipan Das 782254471e5SYonghong Song if (func_info) { 783cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 784254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 785254471e5SYonghong Song func_sig, 786254471e5SYonghong Song sizeof(func_sig)); 787254471e5SYonghong Song } 788254471e5SYonghong Song 789f7f62c71SSandipan Das if (json_output) { 790f7f62c71SSandipan Das jsonw_start_object(json_wtr); 791254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 792254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 793254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 794254471e5SYonghong Song } 795f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 796f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 797f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 798f7f62c71SSandipan Das } else { 799254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 800254471e5SYonghong Song printf("%s:\n", func_sig); 801f7f62c71SSandipan Das printf("%s:\n", sym_name); 802f7f62c71SSandipan Das } 803f7f62c71SSandipan Das 804b053b439SMartin KaFai Lau disasm_print_insn(img, lens[i], opcodes, 805b053b439SMartin KaFai Lau name, disasm_opt, btf, 806b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 807b053b439SMartin KaFai Lau linum); 808b053b439SMartin KaFai Lau 809f7f62c71SSandipan Das img += lens[i]; 810f7f62c71SSandipan Das 811f7f62c71SSandipan Das if (json_output) 812f7f62c71SSandipan Das jsonw_end_object(json_wtr); 813f7f62c71SSandipan Das else 814f7f62c71SSandipan Das printf("\n"); 815f7f62c71SSandipan Das } 816f7f62c71SSandipan Das 817f7f62c71SSandipan Das if (json_output) 818f7f62c71SSandipan Das jsonw_end_array(json_wtr); 819f7f62c71SSandipan Das } else { 820cae73f23SSong Liu disasm_print_insn(buf, member_len, opcodes, name, 821b053b439SMartin KaFai Lau disasm_opt, btf, NULL, 0, 0, false); 822f7f62c71SSandipan Das } 823b6c1cedbSJiong Wang } else if (visual) { 824b6c1cedbSJiong Wang if (json_output) 825b6c1cedbSJiong Wang jsonw_null(json_wtr); 826b6c1cedbSJiong Wang else 827cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 8287105e828SDaniel Borkmann } else { 8297105e828SDaniel Borkmann kernel_syms_load(&dd); 830cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 83109f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 832254471e5SYonghong Song dd.btf = btf; 833254471e5SYonghong Song dd.func_info = func_info; 834cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 835b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 836f84192eeSSandipan Das 837f05e2c32SQuentin Monnet if (json_output) 838cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 839b053b439SMartin KaFai Lau linum); 840f05e2c32SQuentin Monnet else 841cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 842b053b439SMartin KaFai Lau linum); 8437105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8447105e828SDaniel Borkmann } 84571bb428fSJakub Kicinski 846ebbd7f64SQuentin Monnet err = 0; 847369e955bSQuentin Monnet 848ebbd7f64SQuentin Monnet exit_free: 849ebbd7f64SQuentin Monnet btf__free(btf); 850ebbd7f64SQuentin Monnet bpf_prog_linfo__free(prog_linfo); 851ebbd7f64SQuentin Monnet return err; 852ec202509SPaul Chaignon } 85371bb428fSJakub Kicinski 854ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 855ec202509SPaul Chaignon { 856c59765cfSDave Marchevsky struct bpf_prog_info info; 857c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 858c59765cfSDave Marchevsky size_t info_data_sz = 0; 859c59765cfSDave Marchevsky void *info_data = NULL; 860ec202509SPaul Chaignon char *filepath = NULL; 861ec202509SPaul Chaignon bool opcodes = false; 862ec202509SPaul Chaignon bool visual = false; 863ec202509SPaul Chaignon enum dump_mode mode; 864ec202509SPaul Chaignon bool linum = false; 865ec202509SPaul Chaignon int nb_fds, i = 0; 866c59765cfSDave Marchevsky int *fds = NULL; 867ec202509SPaul Chaignon int err = -1; 868ec202509SPaul Chaignon 869ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 870ec202509SPaul Chaignon if (disasm_init()) 87171bb428fSJakub Kicinski return -1; 872ec202509SPaul Chaignon mode = DUMP_JITED; 873ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 874ec202509SPaul Chaignon mode = DUMP_XLATED; 875ec202509SPaul Chaignon } else { 876ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 877ec202509SPaul Chaignon return -1; 878ec202509SPaul Chaignon } 879ec202509SPaul Chaignon NEXT_ARG(); 880ec202509SPaul Chaignon 881ec202509SPaul Chaignon if (argc < 2) 882ec202509SPaul Chaignon usage(); 883ec202509SPaul Chaignon 884ec202509SPaul Chaignon fds = malloc(sizeof(int)); 885ec202509SPaul Chaignon if (!fds) { 886ec202509SPaul Chaignon p_err("mem alloc failed"); 887ec202509SPaul Chaignon return -1; 888ec202509SPaul Chaignon } 889ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 890ec202509SPaul Chaignon if (nb_fds < 1) 891ec202509SPaul Chaignon goto exit_free; 892ec202509SPaul Chaignon 893ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 894ec202509SPaul Chaignon NEXT_ARG(); 895ec202509SPaul Chaignon if (!argc) { 896ec202509SPaul Chaignon p_err("expected file path"); 897ec202509SPaul Chaignon goto exit_close; 898ec202509SPaul Chaignon } 899ec202509SPaul Chaignon if (nb_fds > 1) { 900ec202509SPaul Chaignon p_err("several programs matched"); 901ec202509SPaul Chaignon goto exit_close; 902ec202509SPaul Chaignon } 903ec202509SPaul Chaignon 904ec202509SPaul Chaignon filepath = *argv; 905ec202509SPaul Chaignon NEXT_ARG(); 906ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 907ec202509SPaul Chaignon opcodes = true; 908ec202509SPaul Chaignon NEXT_ARG(); 909ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 910ec202509SPaul Chaignon if (nb_fds > 1) { 911ec202509SPaul Chaignon p_err("several programs matched"); 912ec202509SPaul Chaignon goto exit_close; 913ec202509SPaul Chaignon } 914ec202509SPaul Chaignon 915ec202509SPaul Chaignon visual = true; 916ec202509SPaul Chaignon NEXT_ARG(); 917ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 918ec202509SPaul Chaignon linum = true; 919ec202509SPaul Chaignon NEXT_ARG(); 920ec202509SPaul Chaignon } 921ec202509SPaul Chaignon 922ec202509SPaul Chaignon if (argc) { 923ec202509SPaul Chaignon usage(); 924ec202509SPaul Chaignon goto exit_close; 925ec202509SPaul Chaignon } 926ec202509SPaul Chaignon 927ec202509SPaul Chaignon if (json_output && nb_fds > 1) 928ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 929ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 930c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 931c59765cfSDave Marchevsky 932c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 933c59765cfSDave Marchevsky if (err) { 934c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 935c59765cfSDave Marchevsky break; 936c59765cfSDave Marchevsky } 937c59765cfSDave Marchevsky 938c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 939c59765cfSDave Marchevsky if (err) { 940c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 941c59765cfSDave Marchevsky break; 942c59765cfSDave Marchevsky } 943c59765cfSDave Marchevsky 944c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 945c59765cfSDave Marchevsky if (err) { 946ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 947ec202509SPaul Chaignon break; 948ec202509SPaul Chaignon } 949ec202509SPaul Chaignon 950ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 951ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 952b662000aSRaman Shukhau print_prog_header_json(&info, fds[i]); 953ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 954ec202509SPaul Chaignon } else if (nb_fds > 1) { 955b662000aSRaman Shukhau print_prog_header_plain(&info, fds[i]); 956ec202509SPaul Chaignon } 957ec202509SPaul Chaignon 958c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 959ec202509SPaul Chaignon 960ec202509SPaul Chaignon if (json_output && nb_fds > 1) 961ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 962ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 963ec202509SPaul Chaignon printf("\n"); 964ec202509SPaul Chaignon 965ec202509SPaul Chaignon if (err) 966ec202509SPaul Chaignon break; 967ec202509SPaul Chaignon close(fds[i]); 968ec202509SPaul Chaignon } 969ec202509SPaul Chaignon if (json_output && nb_fds > 1) 970ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 971ec202509SPaul Chaignon 972ec202509SPaul Chaignon exit_close: 973ec202509SPaul Chaignon for (; i < nb_fds; i++) 974ec202509SPaul Chaignon close(fds[i]); 975ec202509SPaul Chaignon exit_free: 976c59765cfSDave Marchevsky free(info_data); 977ec202509SPaul Chaignon free(fds); 978ec202509SPaul Chaignon return err; 97971bb428fSJakub Kicinski } 98071bb428fSJakub Kicinski 98171bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 98271bb428fSJakub Kicinski { 983004b45c0SQuentin Monnet int err; 984004b45c0SQuentin Monnet 98575a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 986004b45c0SQuentin Monnet if (!err && json_output) 987004b45c0SQuentin Monnet jsonw_null(json_wtr); 988004b45c0SQuentin Monnet return err; 98971bb428fSJakub Kicinski } 99071bb428fSJakub Kicinski 9913ff5a4dcSJakub Kicinski struct map_replace { 9923ff5a4dcSJakub Kicinski int idx; 9933ff5a4dcSJakub Kicinski int fd; 9943ff5a4dcSJakub Kicinski char *name; 9953ff5a4dcSJakub Kicinski }; 9963ff5a4dcSJakub Kicinski 997c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 9983ff5a4dcSJakub Kicinski { 9993ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10003ff5a4dcSJakub Kicinski 10013ff5a4dcSJakub Kicinski return a->idx - b->idx; 10023ff5a4dcSJakub Kicinski } 10033ff5a4dcSJakub Kicinski 1004092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1005092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1006092f0892SStanislav Fomichev int *mapfd) 1007092f0892SStanislav Fomichev { 1008092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1009092f0892SStanislav Fomichev return -EINVAL; 1010092f0892SStanislav Fomichev 1011092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1012092f0892SStanislav Fomichev if (*progfd < 0) 1013092f0892SStanislav Fomichev return *progfd; 1014092f0892SStanislav Fomichev 1015092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1016092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1017092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1018092f0892SStanislav Fomichev return -EINVAL; 1019092f0892SStanislav Fomichev } 1020092f0892SStanislav Fomichev 1021092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1022f9b7ff0dSLorenz Bauer *mapfd = 0; 1023092f0892SStanislav Fomichev return 0; 1024092f0892SStanislav Fomichev } 1025092f0892SStanislav Fomichev 1026092f0892SStanislav Fomichev NEXT_ARG(); 1027092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1028092f0892SStanislav Fomichev return -EINVAL; 1029092f0892SStanislav Fomichev 1030092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1031092f0892SStanislav Fomichev if (*mapfd < 0) 1032092f0892SStanislav Fomichev return *mapfd; 1033092f0892SStanislav Fomichev 1034092f0892SStanislav Fomichev return 0; 1035092f0892SStanislav Fomichev } 1036092f0892SStanislav Fomichev 1037b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1038b7d3826cSJohn Fastabend { 1039b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1040092f0892SStanislav Fomichev int err, progfd; 1041092f0892SStanislav Fomichev int mapfd; 1042b7d3826cSJohn Fastabend 1043092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1044092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1045092f0892SStanislav Fomichev if (err) 1046092f0892SStanislav Fomichev return err; 1047b7d3826cSJohn Fastabend 1048b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1049b7d3826cSJohn Fastabend if (err) { 1050b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1051b7d3826cSJohn Fastabend return -EINVAL; 1052b7d3826cSJohn Fastabend } 1053b7d3826cSJohn Fastabend 1054b7d3826cSJohn Fastabend if (json_output) 1055b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1056b7d3826cSJohn Fastabend return 0; 1057b7d3826cSJohn Fastabend } 1058b7d3826cSJohn Fastabend 1059b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1060b7d3826cSJohn Fastabend { 1061b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1062092f0892SStanislav Fomichev int err, progfd; 1063092f0892SStanislav Fomichev int mapfd; 1064b7d3826cSJohn Fastabend 1065092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1066092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1067092f0892SStanislav Fomichev if (err) 1068092f0892SStanislav Fomichev return err; 1069b7d3826cSJohn Fastabend 1070b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1071b7d3826cSJohn Fastabend if (err) { 1072b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1073b7d3826cSJohn Fastabend return -EINVAL; 1074b7d3826cSJohn Fastabend } 1075b7d3826cSJohn Fastabend 1076b7d3826cSJohn Fastabend if (json_output) 1077b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1078b7d3826cSJohn Fastabend return 0; 1079b7d3826cSJohn Fastabend } 108077380998SStanislav Fomichev 1081ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1082ba95c745SQuentin Monnet { 1083ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1084ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1085ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1086ba95c745SQuentin Monnet return -1; 1087ba95c745SQuentin Monnet } 1088ba95c745SQuentin Monnet 1089ba95c745SQuentin Monnet return 0; 1090ba95c745SQuentin Monnet } 1091ba95c745SQuentin Monnet 1092ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1093ba95c745SQuentin Monnet { 1094ba95c745SQuentin Monnet size_t block_size = 256; 1095ba95c745SQuentin Monnet size_t buf_size = block_size; 1096ba95c745SQuentin Monnet size_t nb_read = 0; 1097ba95c745SQuentin Monnet void *tmp; 1098ba95c745SQuentin Monnet FILE *f; 1099ba95c745SQuentin Monnet 1100ba95c745SQuentin Monnet if (!fname) { 1101ba95c745SQuentin Monnet *data_ptr = NULL; 1102ba95c745SQuentin Monnet *size = 0; 1103ba95c745SQuentin Monnet return 0; 1104ba95c745SQuentin Monnet } 1105ba95c745SQuentin Monnet 1106ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1107ba95c745SQuentin Monnet f = stdin; 1108ba95c745SQuentin Monnet else 1109ba95c745SQuentin Monnet f = fopen(fname, "r"); 1110ba95c745SQuentin Monnet if (!f) { 1111ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1112ba95c745SQuentin Monnet return -1; 1113ba95c745SQuentin Monnet } 1114ba95c745SQuentin Monnet 1115ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1116ba95c745SQuentin Monnet if (!*data_ptr) { 1117ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1118ba95c745SQuentin Monnet strerror(errno)); 1119ba95c745SQuentin Monnet goto err_fclose; 1120ba95c745SQuentin Monnet } 1121ba95c745SQuentin Monnet 1122ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1123ba95c745SQuentin Monnet if (feof(f)) 1124ba95c745SQuentin Monnet break; 1125ba95c745SQuentin Monnet if (ferror(f)) { 1126ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1127ba95c745SQuentin Monnet fname, strerror(errno)); 1128ba95c745SQuentin Monnet goto err_free; 1129ba95c745SQuentin Monnet } 1130ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1131ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1132ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1133ba95c745SQuentin Monnet UINT32_MAX); 1134ba95c745SQuentin Monnet goto err_free; 1135ba95c745SQuentin Monnet } 1136ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1137ba95c745SQuentin Monnet buf_size *= 2; 1138ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1139ba95c745SQuentin Monnet if (!tmp) { 1140ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1141ba95c745SQuentin Monnet strerror(errno)); 1142ba95c745SQuentin Monnet goto err_free; 1143ba95c745SQuentin Monnet } 1144ba95c745SQuentin Monnet *data_ptr = tmp; 1145ba95c745SQuentin Monnet } 1146ba95c745SQuentin Monnet } 1147ba95c745SQuentin Monnet if (f != stdin) 1148ba95c745SQuentin Monnet fclose(f); 1149ba95c745SQuentin Monnet 1150ba95c745SQuentin Monnet *size = nb_read; 1151ba95c745SQuentin Monnet return 0; 1152ba95c745SQuentin Monnet 1153ba95c745SQuentin Monnet err_free: 1154ba95c745SQuentin Monnet free(*data_ptr); 1155ba95c745SQuentin Monnet *data_ptr = NULL; 1156ba95c745SQuentin Monnet err_fclose: 1157ba95c745SQuentin Monnet if (f != stdin) 1158ba95c745SQuentin Monnet fclose(f); 1159ba95c745SQuentin Monnet return -1; 1160ba95c745SQuentin Monnet } 1161ba95c745SQuentin Monnet 1162ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1163ba95c745SQuentin Monnet { 1164ba95c745SQuentin Monnet size_t i, j; 1165ba95c745SQuentin Monnet char c; 1166ba95c745SQuentin Monnet 1167ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1168ba95c745SQuentin Monnet /* Row offset */ 1169ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1170ba95c745SQuentin Monnet 1171ba95c745SQuentin Monnet /* Hexadecimal values */ 1172ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1173ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1174ba95c745SQuentin Monnet j % 2 ? " " : ""); 1175ba95c745SQuentin Monnet for (; j < i + 16; j++) 1176ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1177ba95c745SQuentin Monnet 1178ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1179ba95c745SQuentin Monnet fprintf(f, "| "); 1180ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1181ba95c745SQuentin Monnet c = *(char *)(data + j); 1182ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1183ba95c745SQuentin Monnet c = '.'; 1184ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1185ba95c745SQuentin Monnet } 1186ba95c745SQuentin Monnet 1187ba95c745SQuentin Monnet fprintf(f, "\n"); 1188ba95c745SQuentin Monnet } 1189ba95c745SQuentin Monnet } 1190ba95c745SQuentin Monnet 1191ba95c745SQuentin Monnet static int 1192ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1193ba95c745SQuentin Monnet const char *json_key) 1194ba95c745SQuentin Monnet { 1195ba95c745SQuentin Monnet size_t nb_written; 1196ba95c745SQuentin Monnet FILE *f; 1197ba95c745SQuentin Monnet 1198ba95c745SQuentin Monnet if (!fname) 1199ba95c745SQuentin Monnet return 0; 1200ba95c745SQuentin Monnet 1201ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1202ba95c745SQuentin Monnet f = stdout; 1203ba95c745SQuentin Monnet if (json_output) { 1204ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1205ba95c745SQuentin Monnet print_data_json(data, size); 1206ba95c745SQuentin Monnet } else { 1207ba95c745SQuentin Monnet hex_print(data, size, f); 1208ba95c745SQuentin Monnet } 1209ba95c745SQuentin Monnet return 0; 1210ba95c745SQuentin Monnet } 1211ba95c745SQuentin Monnet 1212ba95c745SQuentin Monnet f = fopen(fname, "w"); 1213ba95c745SQuentin Monnet if (!f) { 1214ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1215ba95c745SQuentin Monnet return -1; 1216ba95c745SQuentin Monnet } 1217ba95c745SQuentin Monnet 1218ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1219ba95c745SQuentin Monnet fclose(f); 1220ba95c745SQuentin Monnet if (nb_written != size) { 1221ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1222ba95c745SQuentin Monnet return -1; 1223ba95c745SQuentin Monnet } 1224ba95c745SQuentin Monnet 1225ba95c745SQuentin Monnet return 0; 1226ba95c745SQuentin Monnet } 1227ba95c745SQuentin Monnet 1228ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1229ba95c745SQuentin Monnet { 1230ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1231ba95c745SQuentin Monnet if (!*data_ptr) { 1232ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1233ba95c745SQuentin Monnet strerror(errno)); 1234ba95c745SQuentin Monnet return -1; 1235ba95c745SQuentin Monnet } 1236ba95c745SQuentin Monnet 1237ba95c745SQuentin Monnet return 0; 1238ba95c745SQuentin Monnet } 1239ba95c745SQuentin Monnet 1240ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1241ba95c745SQuentin Monnet { 1242ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1243ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1244ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1245ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1246ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1247ba95c745SQuentin Monnet unsigned int repeat = 1; 1248ba95c745SQuentin Monnet int fd, err; 12499cce5313SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, test_attr); 1250ba95c745SQuentin Monnet 1251ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1252ba95c745SQuentin Monnet return -1; 1253ba95c745SQuentin Monnet 1254ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1255ba95c745SQuentin Monnet if (fd < 0) 1256ba95c745SQuentin Monnet return -1; 1257ba95c745SQuentin Monnet 1258ba95c745SQuentin Monnet while (argc) { 1259ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1260ba95c745SQuentin Monnet "data_size_out", NULL)) 1261ba95c745SQuentin Monnet return -1; 1262ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1263ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1264ba95c745SQuentin Monnet return -1; 1265ba95c745SQuentin Monnet 1266ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1267ba95c745SQuentin Monnet NEXT_ARG(); 1268ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1269ba95c745SQuentin Monnet return -1; 1270ba95c745SQuentin Monnet 1271ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1272ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1273ba95c745SQuentin Monnet return -1; 1274ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1275ba95c745SQuentin Monnet NEXT_ARG(); 1276ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1277ba95c745SQuentin Monnet return -1; 1278ba95c745SQuentin Monnet 1279ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1280ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1281ba95c745SQuentin Monnet char *endptr; 1282ba95c745SQuentin Monnet 1283ba95c745SQuentin Monnet NEXT_ARG(); 1284ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1285ba95c745SQuentin Monnet return -1; 1286ba95c745SQuentin Monnet 1287ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1288ba95c745SQuentin Monnet if (*endptr) { 1289ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1290ba95c745SQuentin Monnet *argv); 1291ba95c745SQuentin Monnet return -1; 1292ba95c745SQuentin Monnet } 1293ba95c745SQuentin Monnet NEXT_ARG(); 1294ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1295ba95c745SQuentin Monnet NEXT_ARG(); 1296ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1297ba95c745SQuentin Monnet return -1; 1298ba95c745SQuentin Monnet 1299ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1300ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1301ba95c745SQuentin Monnet return -1; 1302ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1303ba95c745SQuentin Monnet NEXT_ARG(); 1304ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1305ba95c745SQuentin Monnet return -1; 1306ba95c745SQuentin Monnet 1307ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1308ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1309ba95c745SQuentin Monnet char *endptr; 1310ba95c745SQuentin Monnet 1311ba95c745SQuentin Monnet NEXT_ARG(); 1312ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1313ba95c745SQuentin Monnet return -1; 1314ba95c745SQuentin Monnet 1315ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1316ba95c745SQuentin Monnet if (*endptr) { 1317ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1318ba95c745SQuentin Monnet *argv); 1319ba95c745SQuentin Monnet return -1; 1320ba95c745SQuentin Monnet } 1321ba95c745SQuentin Monnet NEXT_ARG(); 1322ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1323ba95c745SQuentin Monnet char *endptr; 1324ba95c745SQuentin Monnet 1325ba95c745SQuentin Monnet NEXT_ARG(); 1326ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1327ba95c745SQuentin Monnet return -1; 1328ba95c745SQuentin Monnet 1329ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1330ba95c745SQuentin Monnet if (*endptr) { 1331ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1332ba95c745SQuentin Monnet *argv); 1333ba95c745SQuentin Monnet return -1; 1334ba95c745SQuentin Monnet } 1335ba95c745SQuentin Monnet NEXT_ARG(); 1336ba95c745SQuentin Monnet } else { 1337ba95c745SQuentin 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'?", 1338ba95c745SQuentin Monnet *argv); 1339ba95c745SQuentin Monnet return -1; 1340ba95c745SQuentin Monnet } 1341ba95c745SQuentin Monnet } 1342ba95c745SQuentin Monnet 1343ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1344ba95c745SQuentin Monnet if (err) 1345ba95c745SQuentin Monnet return -1; 1346ba95c745SQuentin Monnet 1347ba95c745SQuentin Monnet if (data_in) { 1348ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1349ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1350ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1351ba95c745SQuentin Monnet if (err) 1352ba95c745SQuentin Monnet goto free_data_in; 1353ba95c745SQuentin Monnet } 1354ba95c745SQuentin Monnet 1355ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1356ba95c745SQuentin Monnet if (err) 1357ba95c745SQuentin Monnet goto free_data_out; 1358ba95c745SQuentin Monnet 1359ba95c745SQuentin Monnet if (ctx_in) { 1360ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1361ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1362ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1363ba95c745SQuentin Monnet if (err) 1364ba95c745SQuentin Monnet goto free_ctx_in; 1365ba95c745SQuentin Monnet } 1366ba95c745SQuentin Monnet 1367ba95c745SQuentin Monnet test_attr.repeat = repeat; 1368ba95c745SQuentin Monnet test_attr.data_in = data_in; 1369ba95c745SQuentin Monnet test_attr.data_out = data_out; 1370ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1371ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1372ba95c745SQuentin Monnet 13739cce5313SDelyan Kratunov err = bpf_prog_test_run_opts(fd, &test_attr); 1374ba95c745SQuentin Monnet if (err) { 1375ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1376ba95c745SQuentin Monnet goto free_ctx_out; 1377ba95c745SQuentin Monnet } 1378ba95c745SQuentin Monnet 1379ba95c745SQuentin Monnet err = 0; 1380ba95c745SQuentin Monnet 1381ba95c745SQuentin Monnet if (json_output) 1382ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1383ba95c745SQuentin Monnet 1384ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1385ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1386ba95c745SQuentin Monnet */ 1387ba95c745SQuentin Monnet if (test_attr.data_size_out) 1388ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1389ba95c745SQuentin Monnet test_attr.data_size_out, 1390ba95c745SQuentin Monnet data_fname_out, "data_out"); 1391ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1392ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1393ba95c745SQuentin Monnet test_attr.ctx_size_out, 1394ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1395ba95c745SQuentin Monnet 1396ba95c745SQuentin Monnet if (json_output) { 1397ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1398ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1399ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1400ba95c745SQuentin Monnet } else { 1401ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1402ba95c745SQuentin Monnet test_attr.retval, 1403ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1404ba95c745SQuentin Monnet } 1405ba95c745SQuentin Monnet 1406ba95c745SQuentin Monnet free_ctx_out: 1407ba95c745SQuentin Monnet free(ctx_out); 1408ba95c745SQuentin Monnet free_ctx_in: 1409ba95c745SQuentin Monnet free(ctx_in); 1410ba95c745SQuentin Monnet free_data_out: 1411ba95c745SQuentin Monnet free(data_out); 1412ba95c745SQuentin Monnet free_data_in: 1413ba95c745SQuentin Monnet free(data_in); 1414ba95c745SQuentin Monnet 1415ba95c745SQuentin Monnet return err; 1416ba95c745SQuentin Monnet } 1417ba95c745SQuentin Monnet 14186ae32b29SQuentin Monnet static int 14196ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14206ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14216ae32b29SQuentin Monnet { 14226ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14236ae32b29SQuentin Monnet int ret; 14246ae32b29SQuentin Monnet 14256ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14266ae32b29SQuentin Monnet if (!ret) 14276ae32b29SQuentin Monnet return ret; 14286ae32b29SQuentin Monnet 14296ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14306ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14316ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14326ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14336ae32b29SQuentin Monnet 14346ae32b29SQuentin Monnet return ret; 14356ae32b29SQuentin Monnet } 14366ae32b29SQuentin Monnet 143777380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 143849a086c2SRoman Gushchin { 143932e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1440e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1441e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1442e00aca65SAndrii Nakryiko ); 144355d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 14443ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 144577380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 14463ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 14473767a94bSStanislav Fomichev const char *pinmaps = NULL; 144849a086c2SRoman Gushchin struct bpf_object *obj; 1449c8406848SJakub Kicinski struct bpf_map *map; 1450c8406848SJakub Kicinski const char *pinfile; 14513ff5a4dcSJakub Kicinski unsigned int i, j; 1452c8406848SJakub Kicinski __u32 ifindex = 0; 145332e3e58eSAndrii Nakryiko const char *file; 14543ff5a4dcSJakub Kicinski int idx, err; 145549a086c2SRoman Gushchin 145632e3e58eSAndrii Nakryiko 14578d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 14588d1fc3deSJakub Kicinski return -1; 145932e3e58eSAndrii Nakryiko file = GET_ARG(); 14608d1fc3deSJakub Kicinski pinfile = GET_ARG(); 146149a086c2SRoman Gushchin 1462ba6dd679SJakub Kicinski while (argc) { 146349f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 146449f2cba3SJakub Kicinski NEXT_ARG(); 146549f2cba3SJakub Kicinski 146632e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 146749f2cba3SJakub Kicinski p_err("program type already specified"); 14683ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 146949f2cba3SJakub Kicinski } 147049f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 14713ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 147249f2cba3SJakub Kicinski 1473314f14abSStanislav Fomichev err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1474314f14abSStanislav Fomichev &expected_attach_type); 1475314f14abSStanislav Fomichev if (err < 0) { 147649f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 1477314f14abSStanislav Fomichev char *type = malloc(strlen(*argv) + 2); 1478314f14abSStanislav Fomichev 147949f2cba3SJakub Kicinski if (!type) { 148049f2cba3SJakub Kicinski p_err("mem alloc failed"); 14813ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 148249f2cba3SJakub Kicinski } 148349f2cba3SJakub Kicinski *type = 0; 148449f2cba3SJakub Kicinski strcat(type, *argv); 148549f2cba3SJakub Kicinski strcat(type, "/"); 148649f2cba3SJakub Kicinski 14876ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1488c8406848SJakub Kicinski &expected_attach_type); 148949f2cba3SJakub Kicinski free(type); 1490c76e4c22STaeung Song if (err < 0) 14913ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1492314f14abSStanislav Fomichev } 1493c76e4c22STaeung Song 149449f2cba3SJakub Kicinski NEXT_ARG(); 14953ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1496dde7011aSJakub Kicinski void *new_map_replace; 14973ff5a4dcSJakub Kicinski char *endptr, *name; 14983ff5a4dcSJakub Kicinski int fd; 14993ff5a4dcSJakub Kicinski 15003ff5a4dcSJakub Kicinski NEXT_ARG(); 15013ff5a4dcSJakub Kicinski 15023ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 15033ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15043ff5a4dcSJakub Kicinski 15053ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 15063ff5a4dcSJakub Kicinski NEXT_ARG(); 15073ff5a4dcSJakub Kicinski 15083ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 15093ff5a4dcSJakub Kicinski if (*endptr) { 15103ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 15113ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15123ff5a4dcSJakub Kicinski } 15133ff5a4dcSJakub Kicinski name = NULL; 15143ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 15153ff5a4dcSJakub Kicinski NEXT_ARG(); 15163ff5a4dcSJakub Kicinski 15173ff5a4dcSJakub Kicinski name = *argv; 15183ff5a4dcSJakub Kicinski idx = -1; 15193ff5a4dcSJakub Kicinski } else { 15203ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 15213ff5a4dcSJakub Kicinski *argv); 15223ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15233ff5a4dcSJakub Kicinski } 15243ff5a4dcSJakub Kicinski NEXT_ARG(); 15253ff5a4dcSJakub Kicinski 15263ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 15273ff5a4dcSJakub Kicinski if (fd < 0) 15283ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15293ff5a4dcSJakub Kicinski 1530a19df713SMauricio Vásquez new_map_replace = libbpf_reallocarray(map_replace, 1531dde7011aSJakub Kicinski old_map_fds + 1, 15323ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1533dde7011aSJakub Kicinski if (!new_map_replace) { 15343ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 15353ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15363ff5a4dcSJakub Kicinski } 1537dde7011aSJakub Kicinski map_replace = new_map_replace; 1538dde7011aSJakub Kicinski 15393ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 15403ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 15413ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 15423ff5a4dcSJakub Kicinski old_map_fds++; 154349f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1544ba6dd679SJakub Kicinski NEXT_ARG(); 1545ba6dd679SJakub Kicinski 1546c8406848SJakub Kicinski if (ifindex) { 1547ba6dd679SJakub Kicinski p_err("offload device already specified"); 15483ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1549ba6dd679SJakub Kicinski } 1550ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 15513ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1552ba6dd679SJakub Kicinski 1553c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1554c8406848SJakub Kicinski if (!ifindex) { 1555ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1556ba6dd679SJakub Kicinski *argv, strerror(errno)); 15573ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1558ba6dd679SJakub Kicinski } 1559ba6dd679SJakub Kicinski NEXT_ARG(); 15603767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 15613767a94bSStanislav Fomichev NEXT_ARG(); 15623767a94bSStanislav Fomichev 15633767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 15643767a94bSStanislav Fomichev goto err_free_reuse_maps; 15653767a94bSStanislav Fomichev 15663767a94bSStanislav Fomichev pinmaps = GET_ARG(); 1567ba6dd679SJakub Kicinski } else { 15683ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1569ba6dd679SJakub Kicinski *argv); 15703ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1571ba6dd679SJakub Kicinski } 1572ba6dd679SJakub Kicinski } 1573ba6dd679SJakub Kicinski 1574b59e4ce8SAndrii Nakryiko if (verifier_logs) 1575b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1576b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1577b59e4ce8SAndrii Nakryiko 157832e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1579d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1580c8406848SJakub Kicinski p_err("failed to open object file"); 15813ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 158249a086c2SRoman Gushchin } 158349a086c2SRoman Gushchin 158477380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 158532e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1586c8406848SJakub Kicinski 158732e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1588fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1589c8406848SJakub Kicinski 15906ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1591c8406848SJakub Kicinski &expected_attach_type); 1592c76e4c22STaeung Song if (err < 0) 1593c8406848SJakub Kicinski goto err_close_obj; 1594c8406848SJakub Kicinski } 159577380998SStanislav Fomichev 159677380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 159777380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 159877380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 159977380998SStanislav Fomichev } 1600c8406848SJakub Kicinski 16013ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16023ff5a4dcSJakub Kicinski map_replace_compar); 16033ff5a4dcSJakub Kicinski 16043ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 16053ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 16063ff5a4dcSJakub Kicinski */ 16073ff5a4dcSJakub Kicinski j = 0; 16083ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 16093ff5a4dcSJakub Kicinski i = 0; 1610f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16113ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 16123ff5a4dcSJakub Kicinski map_replace[j].idx = i; 16133ff5a4dcSJakub Kicinski break; 16143ff5a4dcSJakub Kicinski } 16153ff5a4dcSJakub Kicinski i++; 16163ff5a4dcSJakub Kicinski } 16173ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 16183ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 16193ff5a4dcSJakub Kicinski goto err_close_obj; 16203ff5a4dcSJakub Kicinski } 16213ff5a4dcSJakub Kicinski j++; 16223ff5a4dcSJakub Kicinski } 16233ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 16243ff5a4dcSJakub Kicinski if (j) 16253ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16263ff5a4dcSJakub Kicinski map_replace_compar); 16273ff5a4dcSJakub Kicinski 16283ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 16293ff5a4dcSJakub Kicinski j = 0; 16303ff5a4dcSJakub Kicinski idx = 0; 1631f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16329855c131SChristy Lee if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1633c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1634c8406848SJakub Kicinski 16353ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 16363ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 16373ff5a4dcSJakub Kicinski if (err) { 16383ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 16393ff5a4dcSJakub Kicinski goto err_close_obj; 16403ff5a4dcSJakub Kicinski } 16413ff5a4dcSJakub Kicinski 16423ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 16433ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 16443ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 16453ff5a4dcSJakub Kicinski idx); 16463ff5a4dcSJakub Kicinski goto err_close_obj; 16473ff5a4dcSJakub Kicinski } 16483ff5a4dcSJakub Kicinski } 16493ff5a4dcSJakub Kicinski 16503ff5a4dcSJakub Kicinski idx++; 16513ff5a4dcSJakub Kicinski } 16523ff5a4dcSJakub Kicinski if (j < old_map_fds) { 16533ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 16543ff5a4dcSJakub Kicinski goto err_close_obj; 16553ff5a4dcSJakub Kicinski } 16563ff5a4dcSJakub Kicinski 1657b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1658c8406848SJakub Kicinski if (err) { 1659c8406848SJakub Kicinski p_err("failed to load object file"); 1660c8406848SJakub Kicinski goto err_close_obj; 1661c8406848SJakub Kicinski } 1662c8406848SJakub Kicinski 166377380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 166477380998SStanislav Fomichev if (err) 1665bfee71fbSJakub Kicinski goto err_close_obj; 166649a086c2SRoman Gushchin 166777380998SStanislav Fomichev if (first_prog_only) { 16686f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 166977380998SStanislav Fomichev if (!prog) { 167077380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 167177380998SStanislav Fomichev goto err_close_obj; 167277380998SStanislav Fomichev } 167377380998SStanislav Fomichev 167477380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 167577380998SStanislav Fomichev if (err) { 167677380998SStanislav Fomichev p_err("failed to pin program %s", 1677fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 167877380998SStanislav Fomichev goto err_close_obj; 167977380998SStanislav Fomichev } 168077380998SStanislav Fomichev } else { 168177380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 168277380998SStanislav Fomichev if (err) { 168377380998SStanislav Fomichev p_err("failed to pin all programs"); 168477380998SStanislav Fomichev goto err_close_obj; 168577380998SStanislav Fomichev } 168677380998SStanislav Fomichev } 168777380998SStanislav Fomichev 16883767a94bSStanislav Fomichev if (pinmaps) { 16893767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 16903767a94bSStanislav Fomichev if (err) { 16913767a94bSStanislav Fomichev p_err("failed to pin all maps"); 16923767a94bSStanislav Fomichev goto err_unpin; 16933767a94bSStanislav Fomichev } 16943767a94bSStanislav Fomichev } 16953767a94bSStanislav Fomichev 169649a086c2SRoman Gushchin if (json_output) 169749a086c2SRoman Gushchin jsonw_null(json_wtr); 169849a086c2SRoman Gushchin 1699bfee71fbSJakub Kicinski bpf_object__close(obj); 17003ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17013ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17023ff5a4dcSJakub Kicinski free(map_replace); 1703bfee71fbSJakub Kicinski 170449a086c2SRoman Gushchin return 0; 1705bfee71fbSJakub Kicinski 17063767a94bSStanislav Fomichev err_unpin: 17073767a94bSStanislav Fomichev if (first_prog_only) 17083767a94bSStanislav Fomichev unlink(pinfile); 17093767a94bSStanislav Fomichev else 17103767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1711bfee71fbSJakub Kicinski err_close_obj: 1712314f14abSStanislav Fomichev if (!legacy_libbpf) { 1713314f14abSStanislav Fomichev p_info("Warning: bpftool is now running in libbpf strict mode and has more stringent requirements about BPF programs.\n" 1714314f14abSStanislav Fomichev "If it used to work for this object file but now doesn't, see --legacy option for more details.\n"); 1715314f14abSStanislav Fomichev } 1716314f14abSStanislav Fomichev 1717bfee71fbSJakub Kicinski bpf_object__close(obj); 17183ff5a4dcSJakub Kicinski err_free_reuse_maps: 17193ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17203ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17213ff5a4dcSJakub Kicinski free(map_replace); 1722bfee71fbSJakub Kicinski return -1; 172349a086c2SRoman Gushchin } 172449a086c2SRoman Gushchin 1725d510296dSAlexei Starovoitov static int count_open_fds(void) 1726d510296dSAlexei Starovoitov { 1727d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1728d510296dSAlexei Starovoitov struct dirent *de; 1729d510296dSAlexei Starovoitov int cnt = -3; 1730d510296dSAlexei Starovoitov 1731d510296dSAlexei Starovoitov if (!dp) 1732d510296dSAlexei Starovoitov return -1; 1733d510296dSAlexei Starovoitov 1734d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1735d510296dSAlexei Starovoitov cnt++; 1736d510296dSAlexei Starovoitov 1737d510296dSAlexei Starovoitov closedir(dp); 1738d510296dSAlexei Starovoitov return cnt; 1739d510296dSAlexei Starovoitov } 1740d510296dSAlexei Starovoitov 1741d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1742d510296dSAlexei Starovoitov { 1743d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1744d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1745d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1746d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1747d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1748d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1749942df4dcSAlexei Starovoitov char *log_buf = NULL; 1750d510296dSAlexei Starovoitov 1751d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1752d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1753d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1754942df4dcSAlexei Starovoitov if (verifier_logs) { 1755942df4dcSAlexei Starovoitov ctx->log_level = 1 + 2 + 4; 1756d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1757d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1758d510296dSAlexei Starovoitov if (!log_buf) 1759d510296dSAlexei Starovoitov return -ENOMEM; 1760d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1761942df4dcSAlexei Starovoitov } 1762d510296dSAlexei Starovoitov opts.ctx = ctx; 1763d510296dSAlexei Starovoitov opts.data = gen->data; 1764d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1765d510296dSAlexei Starovoitov opts.insns = gen->insns; 1766d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1767d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1768d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1769d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1770942df4dcSAlexei Starovoitov if (err < 0 || verifier_logs) { 1771d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1772942df4dcSAlexei Starovoitov if (fd_delta && err < 0) 1773d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1774d510296dSAlexei Starovoitov fd_delta); 1775d510296dSAlexei Starovoitov } 1776d510296dSAlexei Starovoitov free(log_buf); 1777d510296dSAlexei Starovoitov return err; 1778d510296dSAlexei Starovoitov } 1779d510296dSAlexei Starovoitov 1780d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1781d510296dSAlexei Starovoitov { 1782d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1783d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1784d510296dSAlexei Starovoitov struct bpf_object *obj; 1785d510296dSAlexei Starovoitov const char *file; 1786d510296dSAlexei Starovoitov int err = 0; 1787d510296dSAlexei Starovoitov 1788d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1789d510296dSAlexei Starovoitov return -1; 1790d510296dSAlexei Starovoitov file = GET_ARG(); 1791d510296dSAlexei Starovoitov 1792b59e4ce8SAndrii Nakryiko if (verifier_logs) 1793b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1794b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1795b59e4ce8SAndrii Nakryiko 1796d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1797d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1798d510296dSAlexei Starovoitov p_err("failed to open object file"); 1799d510296dSAlexei Starovoitov goto err_close_obj; 1800d510296dSAlexei Starovoitov } 1801d510296dSAlexei Starovoitov 1802d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1803d510296dSAlexei Starovoitov if (err) 1804d510296dSAlexei Starovoitov goto err_close_obj; 1805d510296dSAlexei Starovoitov 1806b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1807d510296dSAlexei Starovoitov if (err) { 1808d510296dSAlexei Starovoitov p_err("failed to load object file"); 1809d510296dSAlexei Starovoitov goto err_close_obj; 1810d510296dSAlexei Starovoitov } 1811d510296dSAlexei Starovoitov 1812d510296dSAlexei Starovoitov if (verifier_logs) { 1813d510296dSAlexei Starovoitov struct dump_data dd = {}; 1814d510296dSAlexei Starovoitov 1815d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1816d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1817d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1818d510296dSAlexei Starovoitov } 1819d510296dSAlexei Starovoitov err = try_loader(&gen); 1820d510296dSAlexei Starovoitov err_close_obj: 1821d510296dSAlexei Starovoitov bpf_object__close(obj); 1822d510296dSAlexei Starovoitov return err; 1823d510296dSAlexei Starovoitov } 1824d510296dSAlexei Starovoitov 182577380998SStanislav Fomichev static int do_load(int argc, char **argv) 182677380998SStanislav Fomichev { 1827d510296dSAlexei Starovoitov if (use_loader) 1828d510296dSAlexei Starovoitov return do_loader(argc, argv); 182977380998SStanislav Fomichev return load_with_options(argc, argv, true); 183077380998SStanislav Fomichev } 183177380998SStanislav Fomichev 183277380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 183377380998SStanislav Fomichev { 183477380998SStanislav Fomichev return load_with_options(argc, argv, false); 183577380998SStanislav Fomichev } 183677380998SStanislav Fomichev 183747c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 183847c09d6aSSong Liu 183947c09d6aSSong Liu static int do_profile(int argc, char **argv) 184047c09d6aSSong Liu { 184114e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 184247c09d6aSSong Liu return 0; 184347c09d6aSSong Liu } 184447c09d6aSSong Liu 184547c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 184647c09d6aSSong Liu 184747c09d6aSSong Liu #include "profiler.skel.h" 184847c09d6aSSong Liu 184947c09d6aSSong Liu struct profile_metric { 185047c09d6aSSong Liu const char *name; 185147c09d6aSSong Liu struct bpf_perf_event_value val; 185247c09d6aSSong Liu struct perf_event_attr attr; 185347c09d6aSSong Liu bool selected; 185447c09d6aSSong Liu 185547c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 185647c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 185747c09d6aSSong Liu const char *ratio_desc; 185847c09d6aSSong Liu const float ratio_mul; 185947c09d6aSSong Liu } metrics[] = { 186047c09d6aSSong Liu { 186147c09d6aSSong Liu .name = "cycles", 186247c09d6aSSong Liu .attr = { 186347c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 186447c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 186547c09d6aSSong Liu .exclude_user = 1, 186647c09d6aSSong Liu }, 186747c09d6aSSong Liu }, 186847c09d6aSSong Liu { 186947c09d6aSSong Liu .name = "instructions", 187047c09d6aSSong Liu .attr = { 187147c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 187247c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 187347c09d6aSSong Liu .exclude_user = 1, 187447c09d6aSSong Liu }, 187547c09d6aSSong Liu .ratio_metric = 1, 187647c09d6aSSong Liu .ratio_desc = "insns per cycle", 187747c09d6aSSong Liu .ratio_mul = 1.0, 187847c09d6aSSong Liu }, 187947c09d6aSSong Liu { 188047c09d6aSSong Liu .name = "l1d_loads", 188147c09d6aSSong Liu .attr = { 188247c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 188347c09d6aSSong Liu .config = 188447c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 188547c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 188647c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 188747c09d6aSSong Liu .exclude_user = 1, 188847c09d6aSSong Liu }, 188947c09d6aSSong Liu }, 189047c09d6aSSong Liu { 189147c09d6aSSong Liu .name = "llc_misses", 189247c09d6aSSong Liu .attr = { 189347c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 189447c09d6aSSong Liu .config = 189547c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 189647c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 189747c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 189847c09d6aSSong Liu .exclude_user = 1 189947c09d6aSSong Liu }, 190047c09d6aSSong Liu .ratio_metric = 2, 190147c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 190247c09d6aSSong Liu .ratio_mul = 1e6, 190347c09d6aSSong Liu }, 1904450d060eSYonghong Song { 1905450d060eSYonghong Song .name = "itlb_misses", 1906450d060eSYonghong Song .attr = { 1907450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1908450d060eSYonghong Song .config = 1909450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 1910450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1911450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1912450d060eSYonghong Song .exclude_user = 1 1913450d060eSYonghong Song }, 1914450d060eSYonghong Song .ratio_metric = 2, 1915450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 1916450d060eSYonghong Song .ratio_mul = 1e6, 1917450d060eSYonghong Song }, 1918450d060eSYonghong Song { 1919450d060eSYonghong Song .name = "dtlb_misses", 1920450d060eSYonghong Song .attr = { 1921450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1922450d060eSYonghong Song .config = 1923450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 1924450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1925450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 1926450d060eSYonghong Song .exclude_user = 1 1927450d060eSYonghong Song }, 1928450d060eSYonghong Song .ratio_metric = 2, 1929450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 1930450d060eSYonghong Song .ratio_mul = 1e6, 1931450d060eSYonghong Song }, 193247c09d6aSSong Liu }; 193347c09d6aSSong Liu 193447c09d6aSSong Liu static __u64 profile_total_count; 193547c09d6aSSong Liu 193647c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 193747c09d6aSSong Liu 193847c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 193947c09d6aSSong Liu { 194047c09d6aSSong Liu unsigned int metric_cnt; 194147c09d6aSSong Liu int selected_cnt = 0; 194247c09d6aSSong Liu unsigned int i; 194347c09d6aSSong Liu 194447c09d6aSSong Liu metric_cnt = sizeof(metrics) / sizeof(struct profile_metric); 194547c09d6aSSong Liu 194647c09d6aSSong Liu while (argc > 0) { 194747c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 194847c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 194947c09d6aSSong Liu if (!metrics[i].selected) 195047c09d6aSSong Liu selected_cnt++; 195147c09d6aSSong Liu metrics[i].selected = true; 195247c09d6aSSong Liu break; 195347c09d6aSSong Liu } 195447c09d6aSSong Liu } 195547c09d6aSSong Liu if (i == metric_cnt) { 195647c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 195747c09d6aSSong Liu return -1; 195847c09d6aSSong Liu } 195947c09d6aSSong Liu NEXT_ARG(); 196047c09d6aSSong Liu } 196147c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 196247c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 196347c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 196447c09d6aSSong Liu return -1; 196547c09d6aSSong Liu } 196647c09d6aSSong Liu return selected_cnt; 196747c09d6aSSong Liu } 196847c09d6aSSong Liu 196947c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 197047c09d6aSSong Liu { 197147c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 197247c09d6aSSong Liu int reading_map_fd, count_map_fd; 197347c09d6aSSong Liu __u64 counts[num_cpu]; 197447c09d6aSSong Liu __u32 key = 0; 197547c09d6aSSong Liu int err; 197647c09d6aSSong Liu 197747c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 197847c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 197947c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 198047c09d6aSSong Liu p_err("failed to get fd for map"); 198147c09d6aSSong Liu return; 198247c09d6aSSong Liu } 198347c09d6aSSong Liu 198447c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 198547c09d6aSSong Liu if (err) { 198647c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 198747c09d6aSSong Liu return; 198847c09d6aSSong Liu } 198947c09d6aSSong Liu 199047c09d6aSSong Liu profile_total_count = 0; 199147c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 199247c09d6aSSong Liu profile_total_count += counts[cpu]; 199347c09d6aSSong Liu 199447c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 199547c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 199647c09d6aSSong Liu 199747c09d6aSSong Liu if (!metrics[m].selected) 199847c09d6aSSong Liu continue; 199947c09d6aSSong Liu 200047c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 200147c09d6aSSong Liu if (err) { 200247c09d6aSSong Liu p_err("failed to read reading_map: %s", 200347c09d6aSSong Liu strerror(errno)); 200447c09d6aSSong Liu return; 200547c09d6aSSong Liu } 200647c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 200747c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 200847c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 200947c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 201047c09d6aSSong Liu } 201147c09d6aSSong Liu key++; 201247c09d6aSSong Liu } 201347c09d6aSSong Liu } 201447c09d6aSSong Liu 201547c09d6aSSong Liu static void profile_print_readings_json(void) 201647c09d6aSSong Liu { 201747c09d6aSSong Liu __u32 m; 201847c09d6aSSong Liu 201947c09d6aSSong Liu jsonw_start_array(json_wtr); 202047c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 202147c09d6aSSong Liu if (!metrics[m].selected) 202247c09d6aSSong Liu continue; 202347c09d6aSSong Liu jsonw_start_object(json_wtr); 202447c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 202547c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 202647c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 202747c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 202847c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 202947c09d6aSSong Liu 203047c09d6aSSong Liu jsonw_end_object(json_wtr); 203147c09d6aSSong Liu } 203247c09d6aSSong Liu jsonw_end_array(json_wtr); 203347c09d6aSSong Liu } 203447c09d6aSSong Liu 203547c09d6aSSong Liu static void profile_print_readings_plain(void) 203647c09d6aSSong Liu { 203747c09d6aSSong Liu __u32 m; 203847c09d6aSSong Liu 203947c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 204047c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 204147c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 204247c09d6aSSong Liu int r; 204347c09d6aSSong Liu 204447c09d6aSSong Liu if (!metrics[m].selected) 204547c09d6aSSong Liu continue; 204647c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 204747c09d6aSSong Liu 204847c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 204947c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 205047c09d6aSSong Liu metrics[r].val.counter > 0) { 205147c09d6aSSong Liu printf("# %8.2f %-30s", 205247c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 205347c09d6aSSong Liu metrics[r].val.counter, 205447c09d6aSSong Liu metrics[m].ratio_desc); 205547c09d6aSSong Liu } else { 205647c09d6aSSong Liu printf("%-41s", ""); 205747c09d6aSSong Liu } 205847c09d6aSSong Liu 205947c09d6aSSong Liu if (val->enabled > val->running) 206047c09d6aSSong Liu printf("(%4.2f%%)", 206147c09d6aSSong Liu val->running * 100.0 / val->enabled); 206247c09d6aSSong Liu printf("\n"); 206347c09d6aSSong Liu } 206447c09d6aSSong Liu } 206547c09d6aSSong Liu 206647c09d6aSSong Liu static void profile_print_readings(void) 206747c09d6aSSong Liu { 206847c09d6aSSong Liu if (json_output) 206947c09d6aSSong Liu profile_print_readings_json(); 207047c09d6aSSong Liu else 207147c09d6aSSong Liu profile_print_readings_plain(); 207247c09d6aSSong Liu } 207347c09d6aSSong Liu 207447c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 207547c09d6aSSong Liu { 2076c59765cfSDave Marchevsky struct bpf_func_info func_info; 2077c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2078c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 207947c09d6aSSong Liu const struct btf_type *t; 2080c59765cfSDave Marchevsky __u32 func_info_rec_size; 2081369e955bSQuentin Monnet struct btf *btf = NULL; 208247c09d6aSSong Liu char *name = NULL; 2083c59765cfSDave Marchevsky int err; 208447c09d6aSSong Liu 2085c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2086c59765cfSDave Marchevsky if (err) { 2087c59765cfSDave Marchevsky p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd); 2088c59765cfSDave Marchevsky goto out; 208947c09d6aSSong Liu } 209047c09d6aSSong Liu 2091c59765cfSDave Marchevsky if (info.btf_id == 0) { 209247c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 209347c09d6aSSong Liu goto out; 209447c09d6aSSong Liu } 209547c09d6aSSong Liu 2096c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2097c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 2098c59765cfSDave Marchevsky p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd); 2099c59765cfSDave Marchevsky goto out; 2100c59765cfSDave Marchevsky } 2101c59765cfSDave Marchevsky 2102c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2103c59765cfSDave Marchevsky info.nr_func_info = 1; 2104c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2105c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2106c59765cfSDave Marchevsky 2107c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2108c59765cfSDave Marchevsky if (err) { 2109c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2110c59765cfSDave Marchevsky goto out; 2111c59765cfSDave Marchevsky } 2112c59765cfSDave Marchevsky 2113c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 211486f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 211586f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 211686f4b7f2SQuentin Monnet goto out; 211786f4b7f2SQuentin Monnet } 211886f4b7f2SQuentin Monnet 2119c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 212047c09d6aSSong Liu if (!t) { 212147c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2122c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 212347c09d6aSSong Liu goto out; 212447c09d6aSSong Liu } 212547c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 212647c09d6aSSong Liu out: 2127369e955bSQuentin Monnet btf__free(btf); 212847c09d6aSSong Liu return name; 212947c09d6aSSong Liu } 213047c09d6aSSong Liu 213147c09d6aSSong Liu static struct profiler_bpf *profile_obj; 213247c09d6aSSong Liu static int profile_tgt_fd = -1; 213347c09d6aSSong Liu static char *profile_tgt_name; 213447c09d6aSSong Liu static int *profile_perf_events; 213547c09d6aSSong Liu static int profile_perf_event_cnt; 213647c09d6aSSong Liu 213747c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 213847c09d6aSSong Liu { 213947c09d6aSSong Liu int i; 214047c09d6aSSong Liu 214147c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 214247c09d6aSSong Liu close(profile_perf_events[i]); 214347c09d6aSSong Liu 214447c09d6aSSong Liu free(profile_perf_events); 214547c09d6aSSong Liu profile_perf_event_cnt = 0; 214647c09d6aSSong Liu } 214747c09d6aSSong Liu 214847c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 214947c09d6aSSong Liu { 215047c09d6aSSong Liu unsigned int cpu, m; 215147c09d6aSSong Liu int map_fd, pmu_fd; 215247c09d6aSSong Liu 215347c09d6aSSong Liu profile_perf_events = calloc( 215447c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 215547c09d6aSSong Liu if (!profile_perf_events) { 215647c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 215747c09d6aSSong Liu strerror(errno)); 215847c09d6aSSong Liu return -1; 215947c09d6aSSong Liu } 216047c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 216147c09d6aSSong Liu if (map_fd < 0) { 216247c09d6aSSong Liu p_err("failed to get fd for events map"); 216347c09d6aSSong Liu return -1; 216447c09d6aSSong Liu } 216547c09d6aSSong Liu 216647c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 216747c09d6aSSong Liu if (!metrics[m].selected) 216847c09d6aSSong Liu continue; 216947c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 217047c09d6aSSong Liu pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 217147c09d6aSSong Liu -1/*pid*/, cpu, -1/*group_fd*/, 0); 217247c09d6aSSong Liu if (pmu_fd < 0 || 217347c09d6aSSong Liu bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 217447c09d6aSSong Liu &pmu_fd, BPF_ANY) || 217547c09d6aSSong Liu ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 217647c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 217747c09d6aSSong Liu metrics[m].name, cpu); 217847c09d6aSSong Liu return -1; 217947c09d6aSSong Liu } 218047c09d6aSSong Liu profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 218147c09d6aSSong Liu } 218247c09d6aSSong Liu } 218347c09d6aSSong Liu return 0; 218447c09d6aSSong Liu } 218547c09d6aSSong Liu 218647c09d6aSSong Liu static void profile_print_and_cleanup(void) 218747c09d6aSSong Liu { 218847c09d6aSSong Liu profile_close_perf_events(profile_obj); 218947c09d6aSSong Liu profile_read_values(profile_obj); 219047c09d6aSSong Liu profile_print_readings(); 219147c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 219247c09d6aSSong Liu 219347c09d6aSSong Liu close(profile_tgt_fd); 219447c09d6aSSong Liu free(profile_tgt_name); 219547c09d6aSSong Liu } 219647c09d6aSSong Liu 219747c09d6aSSong Liu static void int_exit(int signo) 219847c09d6aSSong Liu { 219947c09d6aSSong Liu profile_print_and_cleanup(); 220047c09d6aSSong Liu exit(0); 220147c09d6aSSong Liu } 220247c09d6aSSong Liu 220347c09d6aSSong Liu static int do_profile(int argc, char **argv) 220447c09d6aSSong Liu { 220547c09d6aSSong Liu int num_metric, num_cpu, err = -1; 220647c09d6aSSong Liu struct bpf_program *prog; 220747c09d6aSSong Liu unsigned long duration; 220847c09d6aSSong Liu char *endptr; 220947c09d6aSSong Liu 221047c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 221147c09d6aSSong Liu if (!REQ_ARGS(3)) 221247c09d6aSSong Liu return -EINVAL; 221347c09d6aSSong Liu 221447c09d6aSSong Liu /* parse target fd */ 221547c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 221647c09d6aSSong Liu if (profile_tgt_fd < 0) { 221747c09d6aSSong Liu p_err("failed to parse fd"); 221847c09d6aSSong Liu return -1; 221947c09d6aSSong Liu } 222047c09d6aSSong Liu 222147c09d6aSSong Liu /* parse profiling optional duration */ 222247c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 222347c09d6aSSong Liu NEXT_ARG(); 222447c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 222547c09d6aSSong Liu if (*endptr) 222647c09d6aSSong Liu usage(); 222747c09d6aSSong Liu NEXT_ARG(); 222847c09d6aSSong Liu } else { 222947c09d6aSSong Liu duration = UINT_MAX; 223047c09d6aSSong Liu } 223147c09d6aSSong Liu 223247c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 223347c09d6aSSong Liu if (num_metric <= 0) 223447c09d6aSSong Liu goto out; 223547c09d6aSSong Liu 223647c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 223747c09d6aSSong Liu if (num_cpu <= 0) { 223847c09d6aSSong Liu p_err("failed to identify number of CPUs"); 223947c09d6aSSong Liu goto out; 224047c09d6aSSong Liu } 224147c09d6aSSong Liu 224247c09d6aSSong Liu profile_obj = profiler_bpf__open(); 224347c09d6aSSong Liu if (!profile_obj) { 224447c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 224547c09d6aSSong Liu goto out; 224647c09d6aSSong Liu } 224747c09d6aSSong Liu 224847c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 224947c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 225047c09d6aSSong Liu 225147c09d6aSSong Liu /* adjust map sizes */ 225239748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu); 225339748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric); 225439748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric); 225539748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.counts, 1); 225647c09d6aSSong Liu 225747c09d6aSSong Liu /* change target name */ 225847c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 225947c09d6aSSong Liu if (!profile_tgt_name) 226047c09d6aSSong Liu goto out; 226147c09d6aSSong Liu 226247c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 226347c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 226447c09d6aSSong Liu profile_tgt_name); 226547c09d6aSSong Liu if (err) { 226647c09d6aSSong Liu p_err("failed to set attach target\n"); 226747c09d6aSSong Liu goto out; 226847c09d6aSSong Liu } 226947c09d6aSSong Liu } 227047c09d6aSSong Liu 227147c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 227247c09d6aSSong Liu if (err) { 227347c09d6aSSong Liu p_err("failed to load profile_obj"); 227447c09d6aSSong Liu goto out; 227547c09d6aSSong Liu } 227647c09d6aSSong Liu 227747c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 227847c09d6aSSong Liu if (err) 227947c09d6aSSong Liu goto out; 228047c09d6aSSong Liu 228147c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 228247c09d6aSSong Liu if (err) { 228347c09d6aSSong Liu p_err("failed to attach profile_obj"); 228447c09d6aSSong Liu goto out; 228547c09d6aSSong Liu } 228647c09d6aSSong Liu signal(SIGINT, int_exit); 228747c09d6aSSong Liu 228847c09d6aSSong Liu sleep(duration); 228947c09d6aSSong Liu profile_print_and_cleanup(); 229047c09d6aSSong Liu return 0; 229147c09d6aSSong Liu 229247c09d6aSSong Liu out: 229347c09d6aSSong Liu profile_close_perf_events(profile_obj); 229447c09d6aSSong Liu if (profile_obj) 229547c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 229647c09d6aSSong Liu close(profile_tgt_fd); 229747c09d6aSSong Liu free(profile_tgt_name); 229847c09d6aSSong Liu return err; 229947c09d6aSSong Liu } 230047c09d6aSSong Liu 230147c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 230247c09d6aSSong Liu 230371bb428fSJakub Kicinski static int do_help(int argc, char **argv) 230471bb428fSJakub Kicinski { 2305004b45c0SQuentin Monnet if (json_output) { 2306004b45c0SQuentin Monnet jsonw_null(json_wtr); 2307004b45c0SQuentin Monnet return 0; 2308004b45c0SQuentin Monnet } 2309004b45c0SQuentin Monnet 231071bb428fSJakub Kicinski fprintf(stderr, 231190040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 231290040351SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 231390040351SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | opcodes | linum }]\n" 231490040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 231590040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 231677380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 23173767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 23183767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 231990040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 232090040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 232190040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2322ba95c745SQuentin Monnet " data_in FILE \\\n" 2323ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2324ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2325ba95c745SQuentin Monnet " [repeat N]\n" 232690040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 232790040351SQuentin Monnet " %1$s %2$s tracelog\n" 232890040351SQuentin Monnet " %1$s %2$s help\n" 232971bb428fSJakub Kicinski "\n" 23303ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 233171bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 233249f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 233349f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 233449f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 233549f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2336f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 233749f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 233849f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 233905ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 234005ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 234105ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2342a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 234393a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 2344b544342eSQuentin Monnet " ATTACH_TYPE := { msg_verdict | skb_verdict | stream_verdict |\n" 2345b544342eSQuentin Monnet " stream_parser | flow_dissector }\n" 2346450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2347c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 23488cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 23498cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 235071bb428fSJakub Kicinski "", 235190040351SQuentin Monnet bin_name, argv[-2]); 235271bb428fSJakub Kicinski 235371bb428fSJakub Kicinski return 0; 235471bb428fSJakub Kicinski } 235571bb428fSJakub Kicinski 235671bb428fSJakub Kicinski static const struct cmd cmds[] = { 235771bb428fSJakub Kicinski { "show", do_show }, 23586ebe6dbdSJakub Kicinski { "list", do_show }, 23599f606179SQuentin Monnet { "help", do_help }, 236071bb428fSJakub Kicinski { "dump", do_dump }, 236171bb428fSJakub Kicinski { "pin", do_pin }, 236249a086c2SRoman Gushchin { "load", do_load }, 236377380998SStanislav Fomichev { "loadall", do_loadall }, 2364b7d3826cSJohn Fastabend { "attach", do_attach }, 2365b7d3826cSJohn Fastabend { "detach", do_detach }, 236630da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2367ba95c745SQuentin Monnet { "run", do_run }, 236847c09d6aSSong Liu { "profile", do_profile }, 236971bb428fSJakub Kicinski { 0 } 237071bb428fSJakub Kicinski }; 237171bb428fSJakub Kicinski 237271bb428fSJakub Kicinski int do_prog(int argc, char **argv) 237371bb428fSJakub Kicinski { 237471bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 237571bb428fSJakub Kicinski } 2376