102ff58dcSJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 202ff58dcSJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 371bb428fSJakub Kicinski 4b3d84af7SQuentin Monnet #ifndef _GNU_SOURCE 53ff5a4dcSJakub Kicinski #define _GNU_SOURCE 6b3d84af7SQuentin Monnet #endif 771bb428fSJakub Kicinski #include <errno.h> 871bb428fSJakub Kicinski #include <fcntl.h> 947c09d6aSSong Liu #include <signal.h> 10c9c35995SJakub Kicinski #include <stdarg.h> 1171bb428fSJakub Kicinski #include <stdio.h> 1271bb428fSJakub Kicinski #include <stdlib.h> 1371bb428fSJakub Kicinski #include <string.h> 1471bb428fSJakub Kicinski #include <time.h> 1571bb428fSJakub Kicinski #include <unistd.h> 16ba6dd679SJakub Kicinski #include <net/if.h> 1747c09d6aSSong Liu #include <sys/ioctl.h> 1871bb428fSJakub Kicinski #include <sys/types.h> 1971bb428fSJakub Kicinski #include <sys/stat.h> 2047c09d6aSSong Liu #include <sys/syscall.h> 21d510296dSAlexei Starovoitov #include <dirent.h> 2271bb428fSJakub Kicinski 23c8406848SJakub Kicinski #include <linux/err.h> 2447c09d6aSSong Liu #include <linux/perf_event.h> 25ba95c745SQuentin Monnet #include <linux/sizes.h> 26c8406848SJakub Kicinski 27229c3b47SToke Høiland-Jørgensen #include <bpf/bpf.h> 28229c3b47SToke Høiland-Jørgensen #include <bpf/btf.h> 298f184732SQuentin Monnet #include <bpf/hashmap.h> 30229c3b47SToke Høiland-Jørgensen #include <bpf/libbpf.h> 31a19df713SMauricio Vásquez #include <bpf/libbpf_internal.h> 32d510296dSAlexei Starovoitov #include <bpf/skel_internal.h> 3371bb428fSJakub Kicinski 34b6c1cedbSJiong Wang #include "cfg.h" 3571bb428fSJakub Kicinski #include "main.h" 3673bb5b4fSJiong Wang #include "xlated_dumper.h" 3771bb428fSJakub Kicinski 38aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX "bpf_metadata_" 39aff52e68SYiFei Zhu #define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1) 40aff52e68SYiFei Zhu 41ec202509SPaul Chaignon enum dump_mode { 42ec202509SPaul Chaignon DUMP_JITED, 43ec202509SPaul Chaignon DUMP_XLATED, 44ec202509SPaul Chaignon }; 45ec202509SPaul Chaignon 461ba5ad36SDaniel Müller static const bool attach_types[] = { 471ba5ad36SDaniel Müller [BPF_SK_SKB_STREAM_PARSER] = true, 481ba5ad36SDaniel Müller [BPF_SK_SKB_STREAM_VERDICT] = true, 491ba5ad36SDaniel Müller [BPF_SK_SKB_VERDICT] = true, 501ba5ad36SDaniel Müller [BPF_SK_MSG_VERDICT] = true, 511ba5ad36SDaniel Müller [BPF_FLOW_DISSECTOR] = true, 521ba5ad36SDaniel Müller [__MAX_BPF_ATTACH_TYPE] = false, 531ba5ad36SDaniel Müller }; 541ba5ad36SDaniel Müller 551ba5ad36SDaniel Müller /* Textual representations traditionally used by the program and kept around 561ba5ad36SDaniel Müller * for the sake of backwards compatibility. 571ba5ad36SDaniel Müller */ 58b7d3826cSJohn Fastabend static const char * const attach_type_strings[] = { 59b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 60b7d3826cSJohn Fastabend [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 61a7ba4558SCong Wang [BPF_SK_SKB_VERDICT] = "skb_verdict", 62b7d3826cSJohn Fastabend [BPF_SK_MSG_VERDICT] = "msg_verdict", 63b7d3826cSJohn Fastabend [__MAX_BPF_ATTACH_TYPE] = NULL, 64b7d3826cSJohn Fastabend }; 65b7d3826cSJohn Fastabend 668f184732SQuentin Monnet static struct hashmap *prog_table; 6746241271SQuentin Monnet 68c101189bSQuentin Monnet static enum bpf_attach_type parse_attach_type(const char *str) 69b7d3826cSJohn Fastabend { 70b7d3826cSJohn Fastabend enum bpf_attach_type type; 71b7d3826cSJohn Fastabend 72b7d3826cSJohn Fastabend for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 731ba5ad36SDaniel Müller if (attach_types[type]) { 741ba5ad36SDaniel Müller const char *attach_type_str; 751ba5ad36SDaniel Müller 761ba5ad36SDaniel Müller attach_type_str = libbpf_bpf_attach_type_str(type); 771ba5ad36SDaniel Müller if (!strcmp(str, attach_type_str)) 781ba5ad36SDaniel Müller return type; 791ba5ad36SDaniel Müller } 801ba5ad36SDaniel Müller 81b7d3826cSJohn Fastabend if (attach_type_strings[type] && 82b7d3826cSJohn Fastabend is_prefix(str, attach_type_strings[type])) 83b7d3826cSJohn Fastabend return type; 84b7d3826cSJohn Fastabend } 85b7d3826cSJohn Fastabend 86b7d3826cSJohn Fastabend return __MAX_BPF_ATTACH_TYPE; 87b7d3826cSJohn Fastabend } 88b7d3826cSJohn Fastabend 89c59765cfSDave Marchevsky static int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 90c59765cfSDave Marchevsky void **info_data, size_t *const info_data_sz) 91c59765cfSDave Marchevsky { 92c59765cfSDave Marchevsky struct bpf_prog_info holder = {}; 93c59765cfSDave Marchevsky size_t needed = 0; 94c59765cfSDave Marchevsky void *ptr; 95c59765cfSDave Marchevsky 96c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 97c59765cfSDave Marchevsky holder.jited_prog_len = info->jited_prog_len; 98c59765cfSDave Marchevsky needed += info->jited_prog_len; 99c59765cfSDave Marchevsky } else { 100c59765cfSDave Marchevsky holder.xlated_prog_len = info->xlated_prog_len; 101c59765cfSDave Marchevsky needed += info->xlated_prog_len; 102c59765cfSDave Marchevsky } 103c59765cfSDave Marchevsky 104c59765cfSDave Marchevsky holder.nr_jited_ksyms = info->nr_jited_ksyms; 105c59765cfSDave Marchevsky needed += info->nr_jited_ksyms * sizeof(__u64); 106c59765cfSDave Marchevsky 107c59765cfSDave Marchevsky holder.nr_jited_func_lens = info->nr_jited_func_lens; 108c59765cfSDave Marchevsky needed += info->nr_jited_func_lens * sizeof(__u32); 109c59765cfSDave Marchevsky 110c59765cfSDave Marchevsky holder.nr_func_info = info->nr_func_info; 111c59765cfSDave Marchevsky holder.func_info_rec_size = info->func_info_rec_size; 112c59765cfSDave Marchevsky needed += info->nr_func_info * info->func_info_rec_size; 113c59765cfSDave Marchevsky 114c59765cfSDave Marchevsky holder.nr_line_info = info->nr_line_info; 115c59765cfSDave Marchevsky holder.line_info_rec_size = info->line_info_rec_size; 116c59765cfSDave Marchevsky needed += info->nr_line_info * info->line_info_rec_size; 117c59765cfSDave Marchevsky 118c59765cfSDave Marchevsky holder.nr_jited_line_info = info->nr_jited_line_info; 119c59765cfSDave Marchevsky holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 120c59765cfSDave Marchevsky needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 121c59765cfSDave Marchevsky 122c59765cfSDave Marchevsky if (needed > *info_data_sz) { 123c59765cfSDave Marchevsky ptr = realloc(*info_data, needed); 124c59765cfSDave Marchevsky if (!ptr) 125c59765cfSDave Marchevsky return -1; 126c59765cfSDave Marchevsky 127c59765cfSDave Marchevsky *info_data = ptr; 128c59765cfSDave Marchevsky *info_data_sz = needed; 129c59765cfSDave Marchevsky } 130c59765cfSDave Marchevsky ptr = *info_data; 131c59765cfSDave Marchevsky 132c59765cfSDave Marchevsky if (mode == DUMP_JITED) { 133c59765cfSDave Marchevsky holder.jited_prog_insns = ptr_to_u64(ptr); 134c59765cfSDave Marchevsky ptr += holder.jited_prog_len; 135c59765cfSDave Marchevsky } else { 136c59765cfSDave Marchevsky holder.xlated_prog_insns = ptr_to_u64(ptr); 137c59765cfSDave Marchevsky ptr += holder.xlated_prog_len; 138c59765cfSDave Marchevsky } 139c59765cfSDave Marchevsky 140c59765cfSDave Marchevsky holder.jited_ksyms = ptr_to_u64(ptr); 141c59765cfSDave Marchevsky ptr += holder.nr_jited_ksyms * sizeof(__u64); 142c59765cfSDave Marchevsky 143c59765cfSDave Marchevsky holder.jited_func_lens = ptr_to_u64(ptr); 144c59765cfSDave Marchevsky ptr += holder.nr_jited_func_lens * sizeof(__u32); 145c59765cfSDave Marchevsky 146c59765cfSDave Marchevsky holder.func_info = ptr_to_u64(ptr); 147c59765cfSDave Marchevsky ptr += holder.nr_func_info * holder.func_info_rec_size; 148c59765cfSDave Marchevsky 149c59765cfSDave Marchevsky holder.line_info = ptr_to_u64(ptr); 150c59765cfSDave Marchevsky ptr += holder.nr_line_info * holder.line_info_rec_size; 151c59765cfSDave Marchevsky 152c59765cfSDave Marchevsky holder.jited_line_info = ptr_to_u64(ptr); 153c59765cfSDave Marchevsky ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 154c59765cfSDave Marchevsky 155c59765cfSDave Marchevsky *info = holder; 156c59765cfSDave Marchevsky return 0; 157c59765cfSDave Marchevsky } 158c59765cfSDave Marchevsky 15971bb428fSJakub Kicinski static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 16071bb428fSJakub Kicinski { 16171bb428fSJakub Kicinski struct timespec real_time_ts, boot_time_ts; 16271bb428fSJakub Kicinski time_t wallclock_secs; 16371bb428fSJakub Kicinski struct tm load_tm; 16471bb428fSJakub Kicinski 16571bb428fSJakub Kicinski buf[--size] = '\0'; 16671bb428fSJakub Kicinski 16771bb428fSJakub Kicinski if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 16871bb428fSJakub Kicinski clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 16971bb428fSJakub Kicinski perror("Can't read clocks"); 17071bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 17171bb428fSJakub Kicinski return; 17271bb428fSJakub Kicinski } 17371bb428fSJakub Kicinski 17471bb428fSJakub Kicinski wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 17507480cbcSJakub Kicinski (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 17607480cbcSJakub Kicinski 1000000000; 17707480cbcSJakub Kicinski 17871bb428fSJakub Kicinski 17971bb428fSJakub Kicinski if (!localtime_r(&wallclock_secs, &load_tm)) { 18071bb428fSJakub Kicinski snprintf(buf, size, "%llu", nsecs / 1000000000); 18171bb428fSJakub Kicinski return; 18271bb428fSJakub Kicinski } 18371bb428fSJakub Kicinski 184a3fe1f6fSQuentin Monnet if (json_output) 185a3fe1f6fSQuentin Monnet strftime(buf, size, "%s", &load_tm); 186a3fe1f6fSQuentin Monnet else 187a3fe1f6fSQuentin Monnet strftime(buf, size, "%FT%T%z", &load_tm); 18871bb428fSJakub Kicinski } 18971bb428fSJakub Kicinski 1906e7e034eSQuentin Monnet static void show_prog_maps(int fd, __u32 num_maps) 19171bb428fSJakub Kicinski { 19271bb428fSJakub Kicinski struct bpf_prog_info info = {}; 19371bb428fSJakub Kicinski __u32 len = sizeof(info); 19471bb428fSJakub Kicinski __u32 map_ids[num_maps]; 19571bb428fSJakub Kicinski unsigned int i; 19671bb428fSJakub Kicinski int err; 19771bb428fSJakub Kicinski 19871bb428fSJakub Kicinski info.nr_map_ids = num_maps; 19971bb428fSJakub Kicinski info.map_ids = ptr_to_u64(map_ids); 20071bb428fSJakub Kicinski 20171bb428fSJakub Kicinski err = bpf_obj_get_info_by_fd(fd, &info, &len); 20271bb428fSJakub Kicinski if (err || !info.nr_map_ids) 20371bb428fSJakub Kicinski return; 20471bb428fSJakub Kicinski 205743cc665SQuentin Monnet if (json_output) { 206743cc665SQuentin Monnet jsonw_name(json_wtr, "map_ids"); 207743cc665SQuentin Monnet jsonw_start_array(json_wtr); 208743cc665SQuentin Monnet for (i = 0; i < info.nr_map_ids; i++) 209743cc665SQuentin Monnet jsonw_uint(json_wtr, map_ids[i]); 210743cc665SQuentin Monnet jsonw_end_array(json_wtr); 211743cc665SQuentin Monnet } else { 21271bb428fSJakub Kicinski printf(" map_ids "); 21371bb428fSJakub Kicinski for (i = 0; i < info.nr_map_ids; i++) 21471bb428fSJakub Kicinski printf("%u%s", map_ids[i], 21571bb428fSJakub Kicinski i == info.nr_map_ids - 1 ? "" : ","); 21671bb428fSJakub Kicinski } 21771bb428fSJakub Kicinski } 21871bb428fSJakub Kicinski 219aff52e68SYiFei Zhu static void *find_metadata(int prog_fd, struct bpf_map_info *map_info) 220aff52e68SYiFei Zhu { 221aff52e68SYiFei Zhu struct bpf_prog_info prog_info; 222aff52e68SYiFei Zhu __u32 prog_info_len; 223aff52e68SYiFei Zhu __u32 map_info_len; 224aff52e68SYiFei Zhu void *value = NULL; 225aff52e68SYiFei Zhu __u32 *map_ids; 226aff52e68SYiFei Zhu int nr_maps; 227aff52e68SYiFei Zhu int key = 0; 228aff52e68SYiFei Zhu int map_fd; 229aff52e68SYiFei Zhu int ret; 230aff52e68SYiFei Zhu __u32 i; 231aff52e68SYiFei Zhu 232aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 233aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 234aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 235aff52e68SYiFei Zhu if (ret) 236aff52e68SYiFei Zhu return NULL; 237aff52e68SYiFei Zhu 238aff52e68SYiFei Zhu if (!prog_info.nr_map_ids) 239aff52e68SYiFei Zhu return NULL; 240aff52e68SYiFei Zhu 241aff52e68SYiFei Zhu map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); 242aff52e68SYiFei Zhu if (!map_ids) 243aff52e68SYiFei Zhu return NULL; 244aff52e68SYiFei Zhu 245aff52e68SYiFei Zhu nr_maps = prog_info.nr_map_ids; 246aff52e68SYiFei Zhu memset(&prog_info, 0, sizeof(prog_info)); 247aff52e68SYiFei Zhu prog_info.nr_map_ids = nr_maps; 248aff52e68SYiFei Zhu prog_info.map_ids = ptr_to_u64(map_ids); 249aff52e68SYiFei Zhu prog_info_len = sizeof(prog_info); 250aff52e68SYiFei Zhu 251aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 252aff52e68SYiFei Zhu if (ret) 253aff52e68SYiFei Zhu goto free_map_ids; 254aff52e68SYiFei Zhu 255aff52e68SYiFei Zhu for (i = 0; i < prog_info.nr_map_ids; i++) { 256aff52e68SYiFei Zhu map_fd = bpf_map_get_fd_by_id(map_ids[i]); 257aff52e68SYiFei Zhu if (map_fd < 0) 258aff52e68SYiFei Zhu goto free_map_ids; 259aff52e68SYiFei Zhu 260aff52e68SYiFei Zhu memset(map_info, 0, sizeof(*map_info)); 261aff52e68SYiFei Zhu map_info_len = sizeof(*map_info); 262aff52e68SYiFei Zhu ret = bpf_obj_get_info_by_fd(map_fd, map_info, &map_info_len); 263aff52e68SYiFei Zhu if (ret < 0) { 264aff52e68SYiFei Zhu close(map_fd); 265aff52e68SYiFei Zhu goto free_map_ids; 266aff52e68SYiFei Zhu } 267aff52e68SYiFei Zhu 268aff52e68SYiFei Zhu if (map_info->type != BPF_MAP_TYPE_ARRAY || 269aff52e68SYiFei Zhu map_info->key_size != sizeof(int) || 270aff52e68SYiFei Zhu map_info->max_entries != 1 || 271aff52e68SYiFei Zhu !map_info->btf_value_type_id || 272aff52e68SYiFei Zhu !strstr(map_info->name, ".rodata")) { 273aff52e68SYiFei Zhu close(map_fd); 274aff52e68SYiFei Zhu continue; 275aff52e68SYiFei Zhu } 276aff52e68SYiFei Zhu 277aff52e68SYiFei Zhu value = malloc(map_info->value_size); 278aff52e68SYiFei Zhu if (!value) { 279aff52e68SYiFei Zhu close(map_fd); 280aff52e68SYiFei Zhu goto free_map_ids; 281aff52e68SYiFei Zhu } 282aff52e68SYiFei Zhu 283aff52e68SYiFei Zhu if (bpf_map_lookup_elem(map_fd, &key, value)) { 284aff52e68SYiFei Zhu close(map_fd); 285aff52e68SYiFei Zhu free(value); 286aff52e68SYiFei Zhu value = NULL; 287aff52e68SYiFei Zhu goto free_map_ids; 288aff52e68SYiFei Zhu } 289aff52e68SYiFei Zhu 290aff52e68SYiFei Zhu close(map_fd); 291aff52e68SYiFei Zhu break; 292aff52e68SYiFei Zhu } 293aff52e68SYiFei Zhu 294aff52e68SYiFei Zhu free_map_ids: 295aff52e68SYiFei Zhu free(map_ids); 296aff52e68SYiFei Zhu return value; 297aff52e68SYiFei Zhu } 298aff52e68SYiFei Zhu 299aff52e68SYiFei Zhu static bool has_metadata_prefix(const char *s) 300aff52e68SYiFei Zhu { 301aff52e68SYiFei Zhu return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0; 302aff52e68SYiFei Zhu } 303aff52e68SYiFei Zhu 304aff52e68SYiFei Zhu static void show_prog_metadata(int fd, __u32 num_maps) 305aff52e68SYiFei Zhu { 306aff52e68SYiFei Zhu const struct btf_type *t_datasec, *t_var; 307aff52e68SYiFei Zhu struct bpf_map_info map_info; 308aff52e68SYiFei Zhu struct btf_var_secinfo *vsi; 309aff52e68SYiFei Zhu bool printed_header = false; 310aff52e68SYiFei Zhu unsigned int i, vlen; 311aff52e68SYiFei Zhu void *value = NULL; 312aff52e68SYiFei Zhu const char *name; 31386f4b7f2SQuentin Monnet struct btf *btf; 314aff52e68SYiFei Zhu int err; 315aff52e68SYiFei Zhu 316aff52e68SYiFei Zhu if (!num_maps) 317aff52e68SYiFei Zhu return; 318aff52e68SYiFei Zhu 319aff52e68SYiFei Zhu memset(&map_info, 0, sizeof(map_info)); 320aff52e68SYiFei Zhu value = find_metadata(fd, &map_info); 321aff52e68SYiFei Zhu if (!value) 322aff52e68SYiFei Zhu return; 323aff52e68SYiFei Zhu 32486f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(map_info.btf_id); 32586f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) 326aff52e68SYiFei Zhu goto out_free; 327aff52e68SYiFei Zhu 328aff52e68SYiFei Zhu t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); 329aff52e68SYiFei Zhu if (!btf_is_datasec(t_datasec)) 330aff52e68SYiFei Zhu goto out_free; 331aff52e68SYiFei Zhu 332aff52e68SYiFei Zhu vlen = btf_vlen(t_datasec); 333aff52e68SYiFei Zhu vsi = btf_var_secinfos(t_datasec); 334aff52e68SYiFei Zhu 335aff52e68SYiFei Zhu /* We don't proceed to check the kinds of the elements of the DATASEC. 336aff52e68SYiFei Zhu * The verifier enforces them to be BTF_KIND_VAR. 337aff52e68SYiFei Zhu */ 338aff52e68SYiFei Zhu 339aff52e68SYiFei Zhu if (json_output) { 340aff52e68SYiFei Zhu struct btf_dumper d = { 341aff52e68SYiFei Zhu .btf = btf, 342aff52e68SYiFei Zhu .jw = json_wtr, 343aff52e68SYiFei Zhu .is_plain_text = false, 344aff52e68SYiFei Zhu }; 345aff52e68SYiFei Zhu 346aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 347aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 348aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 349aff52e68SYiFei Zhu 350aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 351aff52e68SYiFei Zhu continue; 352aff52e68SYiFei Zhu 353aff52e68SYiFei Zhu if (!printed_header) { 354aff52e68SYiFei Zhu jsonw_name(json_wtr, "metadata"); 355aff52e68SYiFei Zhu jsonw_start_object(json_wtr); 356aff52e68SYiFei Zhu printed_header = true; 357aff52e68SYiFei Zhu } 358aff52e68SYiFei Zhu 359aff52e68SYiFei Zhu jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); 360aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 361aff52e68SYiFei Zhu if (err) { 362aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 363aff52e68SYiFei Zhu break; 364aff52e68SYiFei Zhu } 365aff52e68SYiFei Zhu } 366aff52e68SYiFei Zhu if (printed_header) 367aff52e68SYiFei Zhu jsonw_end_object(json_wtr); 368aff52e68SYiFei Zhu } else { 369e89ef634SQuentin Monnet json_writer_t *btf_wtr; 370aff52e68SYiFei Zhu struct btf_dumper d = { 371aff52e68SYiFei Zhu .btf = btf, 372aff52e68SYiFei Zhu .is_plain_text = true, 373aff52e68SYiFei Zhu }; 374aff52e68SYiFei Zhu 375aff52e68SYiFei Zhu for (i = 0; i < vlen; i++, vsi++) { 376aff52e68SYiFei Zhu t_var = btf__type_by_id(btf, vsi->type); 377aff52e68SYiFei Zhu name = btf__name_by_offset(btf, t_var->name_off); 378aff52e68SYiFei Zhu 379aff52e68SYiFei Zhu if (!has_metadata_prefix(name)) 380aff52e68SYiFei Zhu continue; 381aff52e68SYiFei Zhu 382aff52e68SYiFei Zhu if (!printed_header) { 383aff52e68SYiFei Zhu printf("\tmetadata:"); 384e89ef634SQuentin Monnet 385e89ef634SQuentin Monnet btf_wtr = jsonw_new(stdout); 386e89ef634SQuentin Monnet if (!btf_wtr) { 387e89ef634SQuentin Monnet p_err("jsonw alloc failed"); 388e89ef634SQuentin Monnet goto out_free; 389e89ef634SQuentin Monnet } 390e89ef634SQuentin Monnet d.jw = btf_wtr, 391e89ef634SQuentin Monnet 392aff52e68SYiFei Zhu printed_header = true; 393aff52e68SYiFei Zhu } 394aff52e68SYiFei Zhu 395aff52e68SYiFei Zhu printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); 396aff52e68SYiFei Zhu 397aff52e68SYiFei Zhu jsonw_reset(btf_wtr); 398aff52e68SYiFei Zhu err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 399aff52e68SYiFei Zhu if (err) { 400aff52e68SYiFei Zhu p_err("btf dump failed: %d", err); 401aff52e68SYiFei Zhu break; 402aff52e68SYiFei Zhu } 403aff52e68SYiFei Zhu } 404aff52e68SYiFei Zhu if (printed_header) 405aff52e68SYiFei Zhu jsonw_destroy(&btf_wtr); 406aff52e68SYiFei Zhu } 407aff52e68SYiFei Zhu 408aff52e68SYiFei Zhu out_free: 409aff52e68SYiFei Zhu btf__free(btf); 410aff52e68SYiFei Zhu free(value); 411aff52e68SYiFei Zhu } 412aff52e68SYiFei Zhu 413b662000aSRaman Shukhau static void print_prog_header_json(struct bpf_prog_info *info, int fd) 414743cc665SQuentin Monnet { 415b700eeb4SDaniel Müller const char *prog_type_str; 416b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 417b662000aSRaman Shukhau 418743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "id", info->id); 419b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 420b700eeb4SDaniel Müller 421b700eeb4SDaniel Müller if (prog_type_str) 422b700eeb4SDaniel Müller jsonw_string_field(json_wtr, "type", prog_type_str); 42371bb428fSJakub Kicinski else 424743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "type", info->type); 42571bb428fSJakub Kicinski 426b662000aSRaman Shukhau if (*info->name) { 427b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 428b662000aSRaman Shukhau jsonw_string_field(json_wtr, "name", prog_name); 429b662000aSRaman Shukhau } 43071bb428fSJakub Kicinski 431743cc665SQuentin Monnet jsonw_name(json_wtr, "tag"); 432743cc665SQuentin Monnet jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 433743cc665SQuentin Monnet info->tag[0], info->tag[1], info->tag[2], info->tag[3], 434743cc665SQuentin Monnet info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 43571bb428fSJakub Kicinski 4369b984a20SJiri Olsa jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 43788ad472bSAlexei Starovoitov if (info->run_time_ns) { 43888ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 43988ad472bSAlexei Starovoitov jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 44088ad472bSAlexei Starovoitov } 4419ed9e9baSAlexei Starovoitov if (info->recursion_misses) 4429ed9e9baSAlexei Starovoitov jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 443ec202509SPaul Chaignon } 4449b984a20SJiri Olsa 445ec202509SPaul Chaignon static void print_prog_json(struct bpf_prog_info *info, int fd) 446ec202509SPaul Chaignon { 447ec202509SPaul Chaignon char *memlock; 448ec202509SPaul Chaignon 449ec202509SPaul Chaignon jsonw_start_object(json_wtr); 450b662000aSRaman Shukhau print_prog_header_json(info, fd); 45152262210SJakub Kicinski print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 45252262210SJakub Kicinski 453743cc665SQuentin Monnet if (info->load_time) { 45471bb428fSJakub Kicinski char buf[32]; 45571bb428fSJakub Kicinski 456743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 45771bb428fSJakub Kicinski 45871bb428fSJakub Kicinski /* Piggy back on load_time, since 0 uid is a valid one */ 459a3fe1f6fSQuentin Monnet jsonw_name(json_wtr, "loaded_at"); 460a3fe1f6fSQuentin Monnet jsonw_printf(json_wtr, "%s", buf); 461743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 46271bb428fSJakub Kicinski } 46371bb428fSJakub Kicinski 464743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 46571bb428fSJakub Kicinski 466743cc665SQuentin Monnet if (info->jited_prog_len) { 467743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", true); 468743cc665SQuentin Monnet jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 469743cc665SQuentin Monnet } else { 470743cc665SQuentin Monnet jsonw_bool_field(json_wtr, "jited", false); 471743cc665SQuentin Monnet } 472743cc665SQuentin Monnet 473743cc665SQuentin Monnet memlock = get_fdinfo(fd, "memlock"); 474743cc665SQuentin Monnet if (memlock) 475357b3cc3SChris J Arges jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock)); 476743cc665SQuentin Monnet free(memlock); 477743cc665SQuentin Monnet 478743cc665SQuentin Monnet if (info->nr_map_ids) 479743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 480743cc665SQuentin Monnet 481569b0c77SPrashant Bhole if (info->btf_id) 482569b0c77SPrashant Bhole jsonw_int_field(json_wtr, "btf_id", info->btf_id); 483569b0c77SPrashant Bhole 4848f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 4858f184732SQuentin Monnet struct hashmap_entry *entry; 4864990f1f4SPrashant Bhole 4874990f1f4SPrashant Bhole jsonw_name(json_wtr, "pinned"); 4884990f1f4SPrashant Bhole jsonw_start_array(json_wtr); 4898f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 4908f184732SQuentin Monnet u32_as_hash_field(info->id)) 4918f184732SQuentin Monnet jsonw_string(json_wtr, entry->value); 4924990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 4934990f1f4SPrashant Bhole } 4944990f1f4SPrashant Bhole 495d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 496d53dee3fSAndrii Nakryiko 497aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 498aff52e68SYiFei Zhu 499743cc665SQuentin Monnet jsonw_end_object(json_wtr); 500743cc665SQuentin Monnet } 501743cc665SQuentin Monnet 502b662000aSRaman Shukhau static void print_prog_header_plain(struct bpf_prog_info *info, int fd) 503743cc665SQuentin Monnet { 504b700eeb4SDaniel Müller const char *prog_type_str; 505b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 506b662000aSRaman Shukhau 507743cc665SQuentin Monnet printf("%u: ", info->id); 508b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 509b700eeb4SDaniel Müller if (prog_type_str) 510b700eeb4SDaniel Müller printf("%s ", prog_type_str); 511743cc665SQuentin Monnet else 512743cc665SQuentin Monnet printf("type %u ", info->type); 513743cc665SQuentin Monnet 514b662000aSRaman Shukhau if (*info->name) { 515b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 516b662000aSRaman Shukhau printf("name %s ", prog_name); 517b662000aSRaman Shukhau } 518743cc665SQuentin Monnet 519743cc665SQuentin Monnet printf("tag "); 520743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 52152262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5229b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 52388ad472bSAlexei Starovoitov if (info->run_time_ns) 52488ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 52588ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5269ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5279ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 528743cc665SQuentin Monnet printf("\n"); 529ec202509SPaul Chaignon } 530ec202509SPaul Chaignon 531ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 532ec202509SPaul Chaignon { 533ec202509SPaul Chaignon char *memlock; 534ec202509SPaul Chaignon 535b662000aSRaman Shukhau print_prog_header_plain(info, fd); 536743cc665SQuentin Monnet 537743cc665SQuentin Monnet if (info->load_time) { 538743cc665SQuentin Monnet char buf[32]; 539743cc665SQuentin Monnet 540743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 541743cc665SQuentin Monnet 542743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 543743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 544743cc665SQuentin Monnet } 545743cc665SQuentin Monnet 546743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 547743cc665SQuentin Monnet 548743cc665SQuentin Monnet if (info->jited_prog_len) 549743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 55071bb428fSJakub Kicinski else 55171bb428fSJakub Kicinski printf(" not jited"); 55271bb428fSJakub Kicinski 55371bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 55471bb428fSJakub Kicinski if (memlock) 55571bb428fSJakub Kicinski printf(" memlock %sB", memlock); 55671bb428fSJakub Kicinski free(memlock); 55771bb428fSJakub Kicinski 558743cc665SQuentin Monnet if (info->nr_map_ids) 559743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 56071bb428fSJakub Kicinski 5618f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5628f184732SQuentin Monnet struct hashmap_entry *entry; 5634990f1f4SPrashant Bhole 5648f184732SQuentin Monnet hashmap__for_each_key_entry(prog_table, entry, 5658f184732SQuentin Monnet u32_as_hash_field(info->id)) 5668f184732SQuentin Monnet printf("\n\tpinned %s", (char *)entry->value); 5674990f1f4SPrashant Bhole } 5684990f1f4SPrashant Bhole 569569b0c77SPrashant Bhole if (info->btf_id) 570031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 571569b0c77SPrashant Bhole 572d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 573d53dee3fSAndrii Nakryiko 57471bb428fSJakub Kicinski printf("\n"); 575aff52e68SYiFei Zhu 576aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 577743cc665SQuentin Monnet } 578743cc665SQuentin Monnet 579743cc665SQuentin Monnet static int show_prog(int fd) 580743cc665SQuentin Monnet { 581743cc665SQuentin Monnet struct bpf_prog_info info = {}; 582743cc665SQuentin Monnet __u32 len = sizeof(info); 583743cc665SQuentin Monnet int err; 584743cc665SQuentin Monnet 585743cc665SQuentin Monnet err = bpf_obj_get_info_by_fd(fd, &info, &len); 586743cc665SQuentin Monnet if (err) { 5879a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 588743cc665SQuentin Monnet return -1; 589743cc665SQuentin Monnet } 590743cc665SQuentin Monnet 591743cc665SQuentin Monnet if (json_output) 592743cc665SQuentin Monnet print_prog_json(&info, fd); 593743cc665SQuentin Monnet else 594743cc665SQuentin Monnet print_prog_plain(&info, fd); 59571bb428fSJakub Kicinski 59671bb428fSJakub Kicinski return 0; 59771bb428fSJakub Kicinski } 59871bb428fSJakub Kicinski 599ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 600ec202509SPaul Chaignon { 601ec202509SPaul Chaignon int *fds = NULL; 602ec202509SPaul Chaignon int nb_fds, i; 603ec202509SPaul Chaignon int err = -1; 604ec202509SPaul Chaignon 605ec202509SPaul Chaignon fds = malloc(sizeof(int)); 606ec202509SPaul Chaignon if (!fds) { 607ec202509SPaul Chaignon p_err("mem alloc failed"); 608ec202509SPaul Chaignon return -1; 609ec202509SPaul Chaignon } 610ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 611ec202509SPaul Chaignon if (nb_fds < 1) 612ec202509SPaul Chaignon goto exit_free; 613ec202509SPaul Chaignon 614ec202509SPaul Chaignon if (json_output && nb_fds > 1) 615ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 616ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 617ec202509SPaul Chaignon err = show_prog(fds[i]); 618ec202509SPaul Chaignon if (err) { 619ec202509SPaul Chaignon for (; i < nb_fds; i++) 620ec202509SPaul Chaignon close(fds[i]); 621ec202509SPaul Chaignon break; 622ec202509SPaul Chaignon } 623ec202509SPaul Chaignon close(fds[i]); 624ec202509SPaul Chaignon } 625ec202509SPaul Chaignon if (json_output && nb_fds > 1) 626ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 627ec202509SPaul Chaignon 628ec202509SPaul Chaignon exit_free: 629ec202509SPaul Chaignon free(fds); 630ec202509SPaul Chaignon return err; 631ec202509SPaul Chaignon } 632ec202509SPaul Chaignon 63371bb428fSJakub Kicinski static int do_show(int argc, char **argv) 634743cc665SQuentin Monnet { 635743cc665SQuentin Monnet __u32 id = 0; 63671bb428fSJakub Kicinski int err; 63771bb428fSJakub Kicinski int fd; 63871bb428fSJakub Kicinski 63946241271SQuentin Monnet if (show_pinned) { 6408f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6418f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 642622a5b58SMauricio Vásquez if (IS_ERR(prog_table)) { 6438f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6448f184732SQuentin Monnet return -1; 6458f184732SQuentin Monnet } 6468f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 64746241271SQuentin Monnet } 648d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6494990f1f4SPrashant Bhole 650ec202509SPaul Chaignon if (argc == 2) 651ec202509SPaul Chaignon return do_show_subset(argc, argv); 65271bb428fSJakub Kicinski 65371bb428fSJakub Kicinski if (argc) 65471bb428fSJakub Kicinski return BAD_ARG(); 65571bb428fSJakub Kicinski 656743cc665SQuentin Monnet if (json_output) 657743cc665SQuentin Monnet jsonw_start_array(json_wtr); 65871bb428fSJakub Kicinski while (true) { 65971bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 66071bb428fSJakub Kicinski if (err) { 6611739c26dSQuentin Monnet if (errno == ENOENT) { 6621739c26dSQuentin Monnet err = 0; 66371bb428fSJakub Kicinski break; 6641739c26dSQuentin Monnet } 6659a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6669a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 667743cc665SQuentin Monnet err = -1; 668743cc665SQuentin Monnet break; 66971bb428fSJakub Kicinski } 67071bb428fSJakub Kicinski 67171bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 67271bb428fSJakub Kicinski if (fd < 0) { 6738207c6ddSJakub Kicinski if (errno == ENOENT) 6748207c6ddSJakub Kicinski continue; 6759a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 67671bb428fSJakub Kicinski id, strerror(errno)); 677743cc665SQuentin Monnet err = -1; 678743cc665SQuentin Monnet break; 67971bb428fSJakub Kicinski } 68071bb428fSJakub Kicinski 68171bb428fSJakub Kicinski err = show_prog(fd); 68271bb428fSJakub Kicinski close(fd); 68371bb428fSJakub Kicinski if (err) 684743cc665SQuentin Monnet break; 68571bb428fSJakub Kicinski } 68671bb428fSJakub Kicinski 687743cc665SQuentin Monnet if (json_output) 688743cc665SQuentin Monnet jsonw_end_array(json_wtr); 689743cc665SQuentin Monnet 690d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 691d53dee3fSAndrii Nakryiko 69246241271SQuentin Monnet if (show_pinned) 6938f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 69446241271SQuentin Monnet 695743cc665SQuentin Monnet return err; 69671bb428fSJakub Kicinski } 69771bb428fSJakub Kicinski 698ec202509SPaul Chaignon static int 699ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 700ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 70171bb428fSJakub Kicinski { 702b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 7033ddeac67SJakub Kicinski const char *disasm_opt = NULL; 7047105e828SDaniel Borkmann struct dump_data dd = {}; 705cae73f23SSong Liu void *func_info = NULL; 706254471e5SYonghong Song struct btf *btf = NULL; 707254471e5SYonghong Song char func_sig[1024]; 70871bb428fSJakub Kicinski unsigned char *buf; 709cae73f23SSong Liu __u32 member_len; 710ebbd7f64SQuentin Monnet int fd, err = -1; 71171bb428fSJakub Kicinski ssize_t n; 71271bb428fSJakub Kicinski 713cae73f23SSong Liu if (mode == DUMP_JITED) { 7145b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 7159a5ab8bfSQuentin Monnet p_info("no instructions returned"); 716ec202509SPaul Chaignon return -1; 717f84192eeSSandipan Das } 71809f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 719cae73f23SSong Liu member_len = info->jited_prog_len; 720cae73f23SSong Liu } else { /* DUMP_XLATED */ 721d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7227105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 723ec202509SPaul Chaignon return -1; 7247105e828SDaniel Borkmann } 72509f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 726cae73f23SSong Liu member_len = info->xlated_prog_len; 727cae73f23SSong Liu } 7287105e828SDaniel Borkmann 72986f4b7f2SQuentin Monnet if (info->btf_id) { 73086f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 73186f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 732254471e5SYonghong Song p_err("failed to get btf"); 733ec202509SPaul Chaignon return -1; 734254471e5SYonghong Song } 73586f4b7f2SQuentin Monnet } 736254471e5SYonghong Song 73709f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 738cae73f23SSong Liu 739cae73f23SSong Liu if (info->nr_line_info) { 740cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 741b053b439SMartin KaFai Lau if (!prog_linfo) 74210a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 743b053b439SMartin KaFai Lau } 744b053b439SMartin KaFai Lau 74571bb428fSJakub Kicinski if (filepath) { 74671bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 74771bb428fSJakub Kicinski if (fd < 0) { 7489a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 74971bb428fSJakub Kicinski strerror(errno)); 750ebbd7f64SQuentin Monnet goto exit_free; 75171bb428fSJakub Kicinski } 75271bb428fSJakub Kicinski 753cae73f23SSong Liu n = write(fd, buf, member_len); 75471bb428fSJakub Kicinski close(fd); 75509f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7569a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 75771bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 758ebbd7f64SQuentin Monnet goto exit_free; 75971bb428fSJakub Kicinski } 76052c84d36SQuentin Monnet 76152c84d36SQuentin Monnet if (json_output) 76252c84d36SQuentin Monnet jsonw_null(json_wtr); 763cae73f23SSong Liu } else if (mode == DUMP_JITED) { 764e6593596SJiong Wang const char *name = NULL; 765e6593596SJiong Wang 766cae73f23SSong Liu if (info->ifindex) { 767cae73f23SSong Liu name = ifindex_to_bfd_params(info->ifindex, 768cae73f23SSong Liu info->netns_dev, 769cae73f23SSong Liu info->netns_ino, 7703ddeac67SJakub Kicinski &disasm_opt); 771e6593596SJiong Wang if (!name) 772ebbd7f64SQuentin Monnet goto exit_free; 773e6593596SJiong Wang } 774e6593596SJiong Wang 775cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 776f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 777254471e5SYonghong Song struct bpf_func_info *record; 778f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 779f7f62c71SSandipan Das unsigned char *img = buf; 780f7f62c71SSandipan Das __u64 *ksyms = NULL; 781f7f62c71SSandipan Das __u32 *lens; 782f7f62c71SSandipan Das __u32 i; 783cae73f23SSong Liu if (info->nr_jited_ksyms) { 784f7f62c71SSandipan Das kernel_syms_load(&dd); 78509f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 786f7f62c71SSandipan Das } 787f7f62c71SSandipan Das 788f7f62c71SSandipan Das if (json_output) 789f7f62c71SSandipan Das jsonw_start_array(json_wtr); 790f7f62c71SSandipan Das 79109f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 792cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 793f7f62c71SSandipan Das if (ksyms) { 794f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 795f7f62c71SSandipan Das if (sym) 796f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 797f7f62c71SSandipan Das else 798f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 799f7f62c71SSandipan Das } else { 800f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 801f7f62c71SSandipan Das } 802f7f62c71SSandipan Das 803254471e5SYonghong Song if (func_info) { 804cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 805254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 806254471e5SYonghong Song func_sig, 807254471e5SYonghong Song sizeof(func_sig)); 808254471e5SYonghong Song } 809254471e5SYonghong Song 810f7f62c71SSandipan Das if (json_output) { 811f7f62c71SSandipan Das jsonw_start_object(json_wtr); 812254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 813254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 814254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 815254471e5SYonghong Song } 816f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 817f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 818f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 819f7f62c71SSandipan Das } else { 820254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 821254471e5SYonghong Song printf("%s:\n", func_sig); 822f7f62c71SSandipan Das printf("%s:\n", sym_name); 823f7f62c71SSandipan Das } 824f7f62c71SSandipan Das 825*55b4de58SQuentin Monnet if (disasm_print_insn(img, lens[i], opcodes, 826b053b439SMartin KaFai Lau name, disasm_opt, btf, 827b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 828*55b4de58SQuentin Monnet linum)) 829*55b4de58SQuentin Monnet goto exit_free; 830b053b439SMartin KaFai Lau 831f7f62c71SSandipan Das img += lens[i]; 832f7f62c71SSandipan Das 833f7f62c71SSandipan Das if (json_output) 834f7f62c71SSandipan Das jsonw_end_object(json_wtr); 835f7f62c71SSandipan Das else 836f7f62c71SSandipan Das printf("\n"); 837f7f62c71SSandipan Das } 838f7f62c71SSandipan Das 839f7f62c71SSandipan Das if (json_output) 840f7f62c71SSandipan Das jsonw_end_array(json_wtr); 841f7f62c71SSandipan Das } else { 842*55b4de58SQuentin Monnet if (disasm_print_insn(buf, member_len, opcodes, name, 843*55b4de58SQuentin Monnet disasm_opt, btf, NULL, 0, 0, 844*55b4de58SQuentin Monnet false)) 845*55b4de58SQuentin Monnet goto exit_free; 846f7f62c71SSandipan Das } 847b6c1cedbSJiong Wang } else if (visual) { 848b6c1cedbSJiong Wang if (json_output) 849b6c1cedbSJiong Wang jsonw_null(json_wtr); 850b6c1cedbSJiong Wang else 851cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 8527105e828SDaniel Borkmann } else { 8537105e828SDaniel Borkmann kernel_syms_load(&dd); 854cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 85509f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 856254471e5SYonghong Song dd.btf = btf; 857254471e5SYonghong Song dd.func_info = func_info; 858cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 859b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 860f84192eeSSandipan Das 861f05e2c32SQuentin Monnet if (json_output) 862cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 863b053b439SMartin KaFai Lau linum); 864f05e2c32SQuentin Monnet else 865cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 866b053b439SMartin KaFai Lau linum); 8677105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8687105e828SDaniel Borkmann } 86971bb428fSJakub Kicinski 870ebbd7f64SQuentin Monnet err = 0; 871369e955bSQuentin Monnet 872ebbd7f64SQuentin Monnet exit_free: 873ebbd7f64SQuentin Monnet btf__free(btf); 874ebbd7f64SQuentin Monnet bpf_prog_linfo__free(prog_linfo); 875ebbd7f64SQuentin Monnet return err; 876ec202509SPaul Chaignon } 87771bb428fSJakub Kicinski 878ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 879ec202509SPaul Chaignon { 880c59765cfSDave Marchevsky struct bpf_prog_info info; 881c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 882c59765cfSDave Marchevsky size_t info_data_sz = 0; 883c59765cfSDave Marchevsky void *info_data = NULL; 884ec202509SPaul Chaignon char *filepath = NULL; 885ec202509SPaul Chaignon bool opcodes = false; 886ec202509SPaul Chaignon bool visual = false; 887ec202509SPaul Chaignon enum dump_mode mode; 888ec202509SPaul Chaignon bool linum = false; 889ec202509SPaul Chaignon int nb_fds, i = 0; 890c59765cfSDave Marchevsky int *fds = NULL; 891ec202509SPaul Chaignon int err = -1; 892ec202509SPaul Chaignon 893ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 894ec202509SPaul Chaignon if (disasm_init()) 89571bb428fSJakub Kicinski return -1; 896ec202509SPaul Chaignon mode = DUMP_JITED; 897ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 898ec202509SPaul Chaignon mode = DUMP_XLATED; 899ec202509SPaul Chaignon } else { 900ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 901ec202509SPaul Chaignon return -1; 902ec202509SPaul Chaignon } 903ec202509SPaul Chaignon NEXT_ARG(); 904ec202509SPaul Chaignon 905ec202509SPaul Chaignon if (argc < 2) 906ec202509SPaul Chaignon usage(); 907ec202509SPaul Chaignon 908ec202509SPaul Chaignon fds = malloc(sizeof(int)); 909ec202509SPaul Chaignon if (!fds) { 910ec202509SPaul Chaignon p_err("mem alloc failed"); 911ec202509SPaul Chaignon return -1; 912ec202509SPaul Chaignon } 913ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 914ec202509SPaul Chaignon if (nb_fds < 1) 915ec202509SPaul Chaignon goto exit_free; 916ec202509SPaul Chaignon 917ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 918ec202509SPaul Chaignon NEXT_ARG(); 919ec202509SPaul Chaignon if (!argc) { 920ec202509SPaul Chaignon p_err("expected file path"); 921ec202509SPaul Chaignon goto exit_close; 922ec202509SPaul Chaignon } 923ec202509SPaul Chaignon if (nb_fds > 1) { 924ec202509SPaul Chaignon p_err("several programs matched"); 925ec202509SPaul Chaignon goto exit_close; 926ec202509SPaul Chaignon } 927ec202509SPaul Chaignon 928ec202509SPaul Chaignon filepath = *argv; 929ec202509SPaul Chaignon NEXT_ARG(); 930ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 931ec202509SPaul Chaignon opcodes = true; 932ec202509SPaul Chaignon NEXT_ARG(); 933ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 934ec202509SPaul Chaignon if (nb_fds > 1) { 935ec202509SPaul Chaignon p_err("several programs matched"); 936ec202509SPaul Chaignon goto exit_close; 937ec202509SPaul Chaignon } 938ec202509SPaul Chaignon 939ec202509SPaul Chaignon visual = true; 940ec202509SPaul Chaignon NEXT_ARG(); 941ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 942ec202509SPaul Chaignon linum = true; 943ec202509SPaul Chaignon NEXT_ARG(); 944ec202509SPaul Chaignon } 945ec202509SPaul Chaignon 946ec202509SPaul Chaignon if (argc) { 947ec202509SPaul Chaignon usage(); 948ec202509SPaul Chaignon goto exit_close; 949ec202509SPaul Chaignon } 950ec202509SPaul Chaignon 951ec202509SPaul Chaignon if (json_output && nb_fds > 1) 952ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 953ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 954c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 955c59765cfSDave Marchevsky 956c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 957c59765cfSDave Marchevsky if (err) { 958c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 959c59765cfSDave Marchevsky break; 960c59765cfSDave Marchevsky } 961c59765cfSDave Marchevsky 962c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 963c59765cfSDave Marchevsky if (err) { 964c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 965c59765cfSDave Marchevsky break; 966c59765cfSDave Marchevsky } 967c59765cfSDave Marchevsky 968c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(fds[i], &info, &info_len); 969c59765cfSDave Marchevsky if (err) { 970ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 971ec202509SPaul Chaignon break; 972ec202509SPaul Chaignon } 973ec202509SPaul Chaignon 974ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 975ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 976b662000aSRaman Shukhau print_prog_header_json(&info, fds[i]); 977ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 978ec202509SPaul Chaignon } else if (nb_fds > 1) { 979b662000aSRaman Shukhau print_prog_header_plain(&info, fds[i]); 980ec202509SPaul Chaignon } 981ec202509SPaul Chaignon 982c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 983ec202509SPaul Chaignon 984ec202509SPaul Chaignon if (json_output && nb_fds > 1) 985ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 986ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 987ec202509SPaul Chaignon printf("\n"); 988ec202509SPaul Chaignon 989ec202509SPaul Chaignon if (err) 990ec202509SPaul Chaignon break; 991ec202509SPaul Chaignon close(fds[i]); 992ec202509SPaul Chaignon } 993ec202509SPaul Chaignon if (json_output && nb_fds > 1) 994ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 995ec202509SPaul Chaignon 996ec202509SPaul Chaignon exit_close: 997ec202509SPaul Chaignon for (; i < nb_fds; i++) 998ec202509SPaul Chaignon close(fds[i]); 999ec202509SPaul Chaignon exit_free: 1000c59765cfSDave Marchevsky free(info_data); 1001ec202509SPaul Chaignon free(fds); 1002ec202509SPaul Chaignon return err; 100371bb428fSJakub Kicinski } 100471bb428fSJakub Kicinski 100571bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 100671bb428fSJakub Kicinski { 1007004b45c0SQuentin Monnet int err; 1008004b45c0SQuentin Monnet 100975a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 1010004b45c0SQuentin Monnet if (!err && json_output) 1011004b45c0SQuentin Monnet jsonw_null(json_wtr); 1012004b45c0SQuentin Monnet return err; 101371bb428fSJakub Kicinski } 101471bb428fSJakub Kicinski 10153ff5a4dcSJakub Kicinski struct map_replace { 10163ff5a4dcSJakub Kicinski int idx; 10173ff5a4dcSJakub Kicinski int fd; 10183ff5a4dcSJakub Kicinski char *name; 10193ff5a4dcSJakub Kicinski }; 10203ff5a4dcSJakub Kicinski 1021c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 10223ff5a4dcSJakub Kicinski { 10233ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10243ff5a4dcSJakub Kicinski 10253ff5a4dcSJakub Kicinski return a->idx - b->idx; 10263ff5a4dcSJakub Kicinski } 10273ff5a4dcSJakub Kicinski 1028092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1029092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1030092f0892SStanislav Fomichev int *mapfd) 1031092f0892SStanislav Fomichev { 1032092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1033092f0892SStanislav Fomichev return -EINVAL; 1034092f0892SStanislav Fomichev 1035092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1036092f0892SStanislav Fomichev if (*progfd < 0) 1037092f0892SStanislav Fomichev return *progfd; 1038092f0892SStanislav Fomichev 1039092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1040092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1041092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1042092f0892SStanislav Fomichev return -EINVAL; 1043092f0892SStanislav Fomichev } 1044092f0892SStanislav Fomichev 1045092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1046f9b7ff0dSLorenz Bauer *mapfd = 0; 1047092f0892SStanislav Fomichev return 0; 1048092f0892SStanislav Fomichev } 1049092f0892SStanislav Fomichev 1050092f0892SStanislav Fomichev NEXT_ARG(); 1051092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1052092f0892SStanislav Fomichev return -EINVAL; 1053092f0892SStanislav Fomichev 1054092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1055092f0892SStanislav Fomichev if (*mapfd < 0) 1056092f0892SStanislav Fomichev return *mapfd; 1057092f0892SStanislav Fomichev 1058092f0892SStanislav Fomichev return 0; 1059092f0892SStanislav Fomichev } 1060092f0892SStanislav Fomichev 1061b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1062b7d3826cSJohn Fastabend { 1063b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1064092f0892SStanislav Fomichev int err, progfd; 1065092f0892SStanislav Fomichev int mapfd; 1066b7d3826cSJohn Fastabend 1067092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1068092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1069092f0892SStanislav Fomichev if (err) 1070092f0892SStanislav Fomichev return err; 1071b7d3826cSJohn Fastabend 1072b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1073b7d3826cSJohn Fastabend if (err) { 1074b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1075b7d3826cSJohn Fastabend return -EINVAL; 1076b7d3826cSJohn Fastabend } 1077b7d3826cSJohn Fastabend 1078b7d3826cSJohn Fastabend if (json_output) 1079b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1080b7d3826cSJohn Fastabend return 0; 1081b7d3826cSJohn Fastabend } 1082b7d3826cSJohn Fastabend 1083b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1084b7d3826cSJohn Fastabend { 1085b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1086092f0892SStanislav Fomichev int err, progfd; 1087092f0892SStanislav Fomichev int mapfd; 1088b7d3826cSJohn Fastabend 1089092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1090092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1091092f0892SStanislav Fomichev if (err) 1092092f0892SStanislav Fomichev return err; 1093b7d3826cSJohn Fastabend 1094b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1095b7d3826cSJohn Fastabend if (err) { 1096b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1097b7d3826cSJohn Fastabend return -EINVAL; 1098b7d3826cSJohn Fastabend } 1099b7d3826cSJohn Fastabend 1100b7d3826cSJohn Fastabend if (json_output) 1101b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1102b7d3826cSJohn Fastabend return 0; 1103b7d3826cSJohn Fastabend } 110477380998SStanislav Fomichev 1105ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1106ba95c745SQuentin Monnet { 1107ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1108ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1109ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1110ba95c745SQuentin Monnet return -1; 1111ba95c745SQuentin Monnet } 1112ba95c745SQuentin Monnet 1113ba95c745SQuentin Monnet return 0; 1114ba95c745SQuentin Monnet } 1115ba95c745SQuentin Monnet 1116ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1117ba95c745SQuentin Monnet { 1118ba95c745SQuentin Monnet size_t block_size = 256; 1119ba95c745SQuentin Monnet size_t buf_size = block_size; 1120ba95c745SQuentin Monnet size_t nb_read = 0; 1121ba95c745SQuentin Monnet void *tmp; 1122ba95c745SQuentin Monnet FILE *f; 1123ba95c745SQuentin Monnet 1124ba95c745SQuentin Monnet if (!fname) { 1125ba95c745SQuentin Monnet *data_ptr = NULL; 1126ba95c745SQuentin Monnet *size = 0; 1127ba95c745SQuentin Monnet return 0; 1128ba95c745SQuentin Monnet } 1129ba95c745SQuentin Monnet 1130ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1131ba95c745SQuentin Monnet f = stdin; 1132ba95c745SQuentin Monnet else 1133ba95c745SQuentin Monnet f = fopen(fname, "r"); 1134ba95c745SQuentin Monnet if (!f) { 1135ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1136ba95c745SQuentin Monnet return -1; 1137ba95c745SQuentin Monnet } 1138ba95c745SQuentin Monnet 1139ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1140ba95c745SQuentin Monnet if (!*data_ptr) { 1141ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1142ba95c745SQuentin Monnet strerror(errno)); 1143ba95c745SQuentin Monnet goto err_fclose; 1144ba95c745SQuentin Monnet } 1145ba95c745SQuentin Monnet 1146ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1147ba95c745SQuentin Monnet if (feof(f)) 1148ba95c745SQuentin Monnet break; 1149ba95c745SQuentin Monnet if (ferror(f)) { 1150ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1151ba95c745SQuentin Monnet fname, strerror(errno)); 1152ba95c745SQuentin Monnet goto err_free; 1153ba95c745SQuentin Monnet } 1154ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1155ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1156ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1157ba95c745SQuentin Monnet UINT32_MAX); 1158ba95c745SQuentin Monnet goto err_free; 1159ba95c745SQuentin Monnet } 1160ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1161ba95c745SQuentin Monnet buf_size *= 2; 1162ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1163ba95c745SQuentin Monnet if (!tmp) { 1164ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1165ba95c745SQuentin Monnet strerror(errno)); 1166ba95c745SQuentin Monnet goto err_free; 1167ba95c745SQuentin Monnet } 1168ba95c745SQuentin Monnet *data_ptr = tmp; 1169ba95c745SQuentin Monnet } 1170ba95c745SQuentin Monnet } 1171ba95c745SQuentin Monnet if (f != stdin) 1172ba95c745SQuentin Monnet fclose(f); 1173ba95c745SQuentin Monnet 1174ba95c745SQuentin Monnet *size = nb_read; 1175ba95c745SQuentin Monnet return 0; 1176ba95c745SQuentin Monnet 1177ba95c745SQuentin Monnet err_free: 1178ba95c745SQuentin Monnet free(*data_ptr); 1179ba95c745SQuentin Monnet *data_ptr = NULL; 1180ba95c745SQuentin Monnet err_fclose: 1181ba95c745SQuentin Monnet if (f != stdin) 1182ba95c745SQuentin Monnet fclose(f); 1183ba95c745SQuentin Monnet return -1; 1184ba95c745SQuentin Monnet } 1185ba95c745SQuentin Monnet 1186ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1187ba95c745SQuentin Monnet { 1188ba95c745SQuentin Monnet size_t i, j; 1189ba95c745SQuentin Monnet char c; 1190ba95c745SQuentin Monnet 1191ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1192ba95c745SQuentin Monnet /* Row offset */ 1193ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1194ba95c745SQuentin Monnet 1195ba95c745SQuentin Monnet /* Hexadecimal values */ 1196ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1197ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1198ba95c745SQuentin Monnet j % 2 ? " " : ""); 1199ba95c745SQuentin Monnet for (; j < i + 16; j++) 1200ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1201ba95c745SQuentin Monnet 1202ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1203ba95c745SQuentin Monnet fprintf(f, "| "); 1204ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1205ba95c745SQuentin Monnet c = *(char *)(data + j); 1206ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1207ba95c745SQuentin Monnet c = '.'; 1208ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1209ba95c745SQuentin Monnet } 1210ba95c745SQuentin Monnet 1211ba95c745SQuentin Monnet fprintf(f, "\n"); 1212ba95c745SQuentin Monnet } 1213ba95c745SQuentin Monnet } 1214ba95c745SQuentin Monnet 1215ba95c745SQuentin Monnet static int 1216ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1217ba95c745SQuentin Monnet const char *json_key) 1218ba95c745SQuentin Monnet { 1219ba95c745SQuentin Monnet size_t nb_written; 1220ba95c745SQuentin Monnet FILE *f; 1221ba95c745SQuentin Monnet 1222ba95c745SQuentin Monnet if (!fname) 1223ba95c745SQuentin Monnet return 0; 1224ba95c745SQuentin Monnet 1225ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1226ba95c745SQuentin Monnet f = stdout; 1227ba95c745SQuentin Monnet if (json_output) { 1228ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1229ba95c745SQuentin Monnet print_data_json(data, size); 1230ba95c745SQuentin Monnet } else { 1231ba95c745SQuentin Monnet hex_print(data, size, f); 1232ba95c745SQuentin Monnet } 1233ba95c745SQuentin Monnet return 0; 1234ba95c745SQuentin Monnet } 1235ba95c745SQuentin Monnet 1236ba95c745SQuentin Monnet f = fopen(fname, "w"); 1237ba95c745SQuentin Monnet if (!f) { 1238ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1239ba95c745SQuentin Monnet return -1; 1240ba95c745SQuentin Monnet } 1241ba95c745SQuentin Monnet 1242ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1243ba95c745SQuentin Monnet fclose(f); 1244ba95c745SQuentin Monnet if (nb_written != size) { 1245ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1246ba95c745SQuentin Monnet return -1; 1247ba95c745SQuentin Monnet } 1248ba95c745SQuentin Monnet 1249ba95c745SQuentin Monnet return 0; 1250ba95c745SQuentin Monnet } 1251ba95c745SQuentin Monnet 1252ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1253ba95c745SQuentin Monnet { 1254ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1255ba95c745SQuentin Monnet if (!*data_ptr) { 1256ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1257ba95c745SQuentin Monnet strerror(errno)); 1258ba95c745SQuentin Monnet return -1; 1259ba95c745SQuentin Monnet } 1260ba95c745SQuentin Monnet 1261ba95c745SQuentin Monnet return 0; 1262ba95c745SQuentin Monnet } 1263ba95c745SQuentin Monnet 1264ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1265ba95c745SQuentin Monnet { 1266ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1267ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1268ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1269ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1270ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1271ba95c745SQuentin Monnet unsigned int repeat = 1; 1272ba95c745SQuentin Monnet int fd, err; 12739cce5313SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, test_attr); 1274ba95c745SQuentin Monnet 1275ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1276ba95c745SQuentin Monnet return -1; 1277ba95c745SQuentin Monnet 1278ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1279ba95c745SQuentin Monnet if (fd < 0) 1280ba95c745SQuentin Monnet return -1; 1281ba95c745SQuentin Monnet 1282ba95c745SQuentin Monnet while (argc) { 1283ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1284ba95c745SQuentin Monnet "data_size_out", NULL)) 1285ba95c745SQuentin Monnet return -1; 1286ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1287ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1288ba95c745SQuentin Monnet return -1; 1289ba95c745SQuentin Monnet 1290ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1291ba95c745SQuentin Monnet NEXT_ARG(); 1292ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1293ba95c745SQuentin Monnet return -1; 1294ba95c745SQuentin Monnet 1295ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1296ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1297ba95c745SQuentin Monnet return -1; 1298ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1299ba95c745SQuentin Monnet NEXT_ARG(); 1300ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1301ba95c745SQuentin Monnet return -1; 1302ba95c745SQuentin Monnet 1303ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1304ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1305ba95c745SQuentin Monnet char *endptr; 1306ba95c745SQuentin Monnet 1307ba95c745SQuentin Monnet NEXT_ARG(); 1308ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1309ba95c745SQuentin Monnet return -1; 1310ba95c745SQuentin Monnet 1311ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1312ba95c745SQuentin Monnet if (*endptr) { 1313ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1314ba95c745SQuentin Monnet *argv); 1315ba95c745SQuentin Monnet return -1; 1316ba95c745SQuentin Monnet } 1317ba95c745SQuentin Monnet NEXT_ARG(); 1318ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1319ba95c745SQuentin Monnet NEXT_ARG(); 1320ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1321ba95c745SQuentin Monnet return -1; 1322ba95c745SQuentin Monnet 1323ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1324ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1325ba95c745SQuentin Monnet return -1; 1326ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1327ba95c745SQuentin Monnet NEXT_ARG(); 1328ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1329ba95c745SQuentin Monnet return -1; 1330ba95c745SQuentin Monnet 1331ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1332ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1333ba95c745SQuentin Monnet char *endptr; 1334ba95c745SQuentin Monnet 1335ba95c745SQuentin Monnet NEXT_ARG(); 1336ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1337ba95c745SQuentin Monnet return -1; 1338ba95c745SQuentin Monnet 1339ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1340ba95c745SQuentin Monnet if (*endptr) { 1341ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1342ba95c745SQuentin Monnet *argv); 1343ba95c745SQuentin Monnet return -1; 1344ba95c745SQuentin Monnet } 1345ba95c745SQuentin Monnet NEXT_ARG(); 1346ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1347ba95c745SQuentin Monnet char *endptr; 1348ba95c745SQuentin Monnet 1349ba95c745SQuentin Monnet NEXT_ARG(); 1350ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1351ba95c745SQuentin Monnet return -1; 1352ba95c745SQuentin Monnet 1353ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1354ba95c745SQuentin Monnet if (*endptr) { 1355ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1356ba95c745SQuentin Monnet *argv); 1357ba95c745SQuentin Monnet return -1; 1358ba95c745SQuentin Monnet } 1359ba95c745SQuentin Monnet NEXT_ARG(); 1360ba95c745SQuentin Monnet } else { 1361ba95c745SQuentin 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'?", 1362ba95c745SQuentin Monnet *argv); 1363ba95c745SQuentin Monnet return -1; 1364ba95c745SQuentin Monnet } 1365ba95c745SQuentin Monnet } 1366ba95c745SQuentin Monnet 1367ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1368ba95c745SQuentin Monnet if (err) 1369ba95c745SQuentin Monnet return -1; 1370ba95c745SQuentin Monnet 1371ba95c745SQuentin Monnet if (data_in) { 1372ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1373ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1374ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1375ba95c745SQuentin Monnet if (err) 1376ba95c745SQuentin Monnet goto free_data_in; 1377ba95c745SQuentin Monnet } 1378ba95c745SQuentin Monnet 1379ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1380ba95c745SQuentin Monnet if (err) 1381ba95c745SQuentin Monnet goto free_data_out; 1382ba95c745SQuentin Monnet 1383ba95c745SQuentin Monnet if (ctx_in) { 1384ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1385ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1386ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1387ba95c745SQuentin Monnet if (err) 1388ba95c745SQuentin Monnet goto free_ctx_in; 1389ba95c745SQuentin Monnet } 1390ba95c745SQuentin Monnet 1391ba95c745SQuentin Monnet test_attr.repeat = repeat; 1392ba95c745SQuentin Monnet test_attr.data_in = data_in; 1393ba95c745SQuentin Monnet test_attr.data_out = data_out; 1394ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1395ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1396ba95c745SQuentin Monnet 13979cce5313SDelyan Kratunov err = bpf_prog_test_run_opts(fd, &test_attr); 1398ba95c745SQuentin Monnet if (err) { 1399ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1400ba95c745SQuentin Monnet goto free_ctx_out; 1401ba95c745SQuentin Monnet } 1402ba95c745SQuentin Monnet 1403ba95c745SQuentin Monnet err = 0; 1404ba95c745SQuentin Monnet 1405ba95c745SQuentin Monnet if (json_output) 1406ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1407ba95c745SQuentin Monnet 1408ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1409ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1410ba95c745SQuentin Monnet */ 1411ba95c745SQuentin Monnet if (test_attr.data_size_out) 1412ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1413ba95c745SQuentin Monnet test_attr.data_size_out, 1414ba95c745SQuentin Monnet data_fname_out, "data_out"); 1415ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1416ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1417ba95c745SQuentin Monnet test_attr.ctx_size_out, 1418ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1419ba95c745SQuentin Monnet 1420ba95c745SQuentin Monnet if (json_output) { 1421ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1422ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1423ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1424ba95c745SQuentin Monnet } else { 1425ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1426ba95c745SQuentin Monnet test_attr.retval, 1427ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1428ba95c745SQuentin Monnet } 1429ba95c745SQuentin Monnet 1430ba95c745SQuentin Monnet free_ctx_out: 1431ba95c745SQuentin Monnet free(ctx_out); 1432ba95c745SQuentin Monnet free_ctx_in: 1433ba95c745SQuentin Monnet free(ctx_in); 1434ba95c745SQuentin Monnet free_data_out: 1435ba95c745SQuentin Monnet free(data_out); 1436ba95c745SQuentin Monnet free_data_in: 1437ba95c745SQuentin Monnet free(data_in); 1438ba95c745SQuentin Monnet 1439ba95c745SQuentin Monnet return err; 1440ba95c745SQuentin Monnet } 1441ba95c745SQuentin Monnet 14426ae32b29SQuentin Monnet static int 14436ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14446ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14456ae32b29SQuentin Monnet { 14466ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14476ae32b29SQuentin Monnet int ret; 14486ae32b29SQuentin Monnet 14496ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14506ae32b29SQuentin Monnet if (!ret) 14516ae32b29SQuentin Monnet return ret; 14526ae32b29SQuentin Monnet 14536ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14546ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14556ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14566ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14576ae32b29SQuentin Monnet 14586ae32b29SQuentin Monnet return ret; 14596ae32b29SQuentin Monnet } 14606ae32b29SQuentin Monnet 146119526e70SWang Yufen static int 146219526e70SWang Yufen auto_attach_program(struct bpf_program *prog, const char *path) 146319526e70SWang Yufen { 146419526e70SWang Yufen struct bpf_link *link; 146519526e70SWang Yufen int err; 146619526e70SWang Yufen 146719526e70SWang Yufen link = bpf_program__attach(prog); 146819526e70SWang Yufen if (!link) { 146919526e70SWang Yufen p_info("Program %s does not support autoattach, falling back to pinning", 147019526e70SWang Yufen bpf_program__name(prog)); 147119526e70SWang Yufen return bpf_obj_pin(bpf_program__fd(prog), path); 147219526e70SWang Yufen } 147319526e70SWang Yufen 147419526e70SWang Yufen err = bpf_link__pin(link, path); 147519526e70SWang Yufen bpf_link__destroy(link); 147619526e70SWang Yufen return err; 147719526e70SWang Yufen } 147819526e70SWang Yufen 147919526e70SWang Yufen static int pathname_concat(char *buf, size_t buf_sz, const char *path, const char *name) 148019526e70SWang Yufen { 148119526e70SWang Yufen int len; 148219526e70SWang Yufen 148319526e70SWang Yufen len = snprintf(buf, buf_sz, "%s/%s", path, name); 148419526e70SWang Yufen if (len < 0) 148519526e70SWang Yufen return -EINVAL; 148619526e70SWang Yufen if ((size_t)len >= buf_sz) 148719526e70SWang Yufen return -ENAMETOOLONG; 148819526e70SWang Yufen 148919526e70SWang Yufen return 0; 149019526e70SWang Yufen } 149119526e70SWang Yufen 149219526e70SWang Yufen static int 149319526e70SWang Yufen auto_attach_programs(struct bpf_object *obj, const char *path) 149419526e70SWang Yufen { 149519526e70SWang Yufen struct bpf_program *prog; 149619526e70SWang Yufen char buf[PATH_MAX]; 149719526e70SWang Yufen int err; 149819526e70SWang Yufen 149919526e70SWang Yufen bpf_object__for_each_program(prog, obj) { 150019526e70SWang Yufen err = pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog)); 150119526e70SWang Yufen if (err) 150219526e70SWang Yufen goto err_unpin_programs; 150319526e70SWang Yufen 150419526e70SWang Yufen err = auto_attach_program(prog, buf); 150519526e70SWang Yufen if (err) 150619526e70SWang Yufen goto err_unpin_programs; 150719526e70SWang Yufen } 150819526e70SWang Yufen 150919526e70SWang Yufen return 0; 151019526e70SWang Yufen 151119526e70SWang Yufen err_unpin_programs: 151219526e70SWang Yufen while ((prog = bpf_object__prev_program(obj, prog))) { 151319526e70SWang Yufen if (pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog))) 151419526e70SWang Yufen continue; 151519526e70SWang Yufen 151619526e70SWang Yufen bpf_program__unpin(prog, buf); 151719526e70SWang Yufen } 151819526e70SWang Yufen 151919526e70SWang Yufen return err; 152019526e70SWang Yufen } 152119526e70SWang Yufen 152277380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 152349a086c2SRoman Gushchin { 152432e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1525e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1526e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1527e00aca65SAndrii Nakryiko ); 152855d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 15293ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 153077380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 15313ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 15323767a94bSStanislav Fomichev const char *pinmaps = NULL; 153319526e70SWang Yufen bool auto_attach = false; 153449a086c2SRoman Gushchin struct bpf_object *obj; 1535c8406848SJakub Kicinski struct bpf_map *map; 1536c8406848SJakub Kicinski const char *pinfile; 15373ff5a4dcSJakub Kicinski unsigned int i, j; 1538c8406848SJakub Kicinski __u32 ifindex = 0; 153932e3e58eSAndrii Nakryiko const char *file; 15403ff5a4dcSJakub Kicinski int idx, err; 154149a086c2SRoman Gushchin 154232e3e58eSAndrii Nakryiko 15438d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 15448d1fc3deSJakub Kicinski return -1; 154532e3e58eSAndrii Nakryiko file = GET_ARG(); 15468d1fc3deSJakub Kicinski pinfile = GET_ARG(); 154749a086c2SRoman Gushchin 1548ba6dd679SJakub Kicinski while (argc) { 154949f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 155049f2cba3SJakub Kicinski NEXT_ARG(); 155149f2cba3SJakub Kicinski 155232e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 155349f2cba3SJakub Kicinski p_err("program type already specified"); 15543ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 155549f2cba3SJakub Kicinski } 155649f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 15573ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 155849f2cba3SJakub Kicinski 1559314f14abSStanislav Fomichev err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1560314f14abSStanislav Fomichev &expected_attach_type); 1561314f14abSStanislav Fomichev if (err < 0) { 156249f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 1563314f14abSStanislav Fomichev char *type = malloc(strlen(*argv) + 2); 1564314f14abSStanislav Fomichev 156549f2cba3SJakub Kicinski if (!type) { 156649f2cba3SJakub Kicinski p_err("mem alloc failed"); 15673ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 156849f2cba3SJakub Kicinski } 156949f2cba3SJakub Kicinski *type = 0; 157049f2cba3SJakub Kicinski strcat(type, *argv); 157149f2cba3SJakub Kicinski strcat(type, "/"); 157249f2cba3SJakub Kicinski 15736ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1574c8406848SJakub Kicinski &expected_attach_type); 157549f2cba3SJakub Kicinski free(type); 1576c76e4c22STaeung Song if (err < 0) 15773ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1578314f14abSStanislav Fomichev } 1579c76e4c22STaeung Song 158049f2cba3SJakub Kicinski NEXT_ARG(); 15813ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1582dde7011aSJakub Kicinski void *new_map_replace; 15833ff5a4dcSJakub Kicinski char *endptr, *name; 15843ff5a4dcSJakub Kicinski int fd; 15853ff5a4dcSJakub Kicinski 15863ff5a4dcSJakub Kicinski NEXT_ARG(); 15873ff5a4dcSJakub Kicinski 15883ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 15893ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15903ff5a4dcSJakub Kicinski 15913ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 15923ff5a4dcSJakub Kicinski NEXT_ARG(); 15933ff5a4dcSJakub Kicinski 15943ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 15953ff5a4dcSJakub Kicinski if (*endptr) { 15963ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 15973ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15983ff5a4dcSJakub Kicinski } 15993ff5a4dcSJakub Kicinski name = NULL; 16003ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 16013ff5a4dcSJakub Kicinski NEXT_ARG(); 16023ff5a4dcSJakub Kicinski 16033ff5a4dcSJakub Kicinski name = *argv; 16043ff5a4dcSJakub Kicinski idx = -1; 16053ff5a4dcSJakub Kicinski } else { 16063ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 16073ff5a4dcSJakub Kicinski *argv); 16083ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16093ff5a4dcSJakub Kicinski } 16103ff5a4dcSJakub Kicinski NEXT_ARG(); 16113ff5a4dcSJakub Kicinski 16123ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 16133ff5a4dcSJakub Kicinski if (fd < 0) 16143ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16153ff5a4dcSJakub Kicinski 1616a19df713SMauricio Vásquez new_map_replace = libbpf_reallocarray(map_replace, 1617dde7011aSJakub Kicinski old_map_fds + 1, 16183ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1619dde7011aSJakub Kicinski if (!new_map_replace) { 16203ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 16213ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16223ff5a4dcSJakub Kicinski } 1623dde7011aSJakub Kicinski map_replace = new_map_replace; 1624dde7011aSJakub Kicinski 16253ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 16263ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 16273ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 16283ff5a4dcSJakub Kicinski old_map_fds++; 162949f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1630ba6dd679SJakub Kicinski NEXT_ARG(); 1631ba6dd679SJakub Kicinski 1632c8406848SJakub Kicinski if (ifindex) { 1633ba6dd679SJakub Kicinski p_err("offload device already specified"); 16343ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1635ba6dd679SJakub Kicinski } 1636ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 16373ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1638ba6dd679SJakub Kicinski 1639c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1640c8406848SJakub Kicinski if (!ifindex) { 1641ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1642ba6dd679SJakub Kicinski *argv, strerror(errno)); 16433ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1644ba6dd679SJakub Kicinski } 1645ba6dd679SJakub Kicinski NEXT_ARG(); 16463767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 16473767a94bSStanislav Fomichev NEXT_ARG(); 16483767a94bSStanislav Fomichev 16493767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 16503767a94bSStanislav Fomichev goto err_free_reuse_maps; 16513767a94bSStanislav Fomichev 16523767a94bSStanislav Fomichev pinmaps = GET_ARG(); 165319526e70SWang Yufen } else if (is_prefix(*argv, "autoattach")) { 165419526e70SWang Yufen auto_attach = true; 165519526e70SWang Yufen NEXT_ARG(); 1656ba6dd679SJakub Kicinski } else { 16573ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1658ba6dd679SJakub Kicinski *argv); 16593ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1660ba6dd679SJakub Kicinski } 1661ba6dd679SJakub Kicinski } 1662ba6dd679SJakub Kicinski 16636b4384ffSQuentin Monnet set_max_rlimit(); 16646b4384ffSQuentin Monnet 1665b59e4ce8SAndrii Nakryiko if (verifier_logs) 1666b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1667b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1668b59e4ce8SAndrii Nakryiko 166932e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1670d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1671c8406848SJakub Kicinski p_err("failed to open object file"); 16723ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 167349a086c2SRoman Gushchin } 167449a086c2SRoman Gushchin 167577380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 167632e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1677c8406848SJakub Kicinski 167832e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1679fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1680c8406848SJakub Kicinski 16816ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1682c8406848SJakub Kicinski &expected_attach_type); 1683c76e4c22STaeung Song if (err < 0) 1684c8406848SJakub Kicinski goto err_close_obj; 1685c8406848SJakub Kicinski } 168677380998SStanislav Fomichev 168777380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 168877380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 168977380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 169077380998SStanislav Fomichev } 1691c8406848SJakub Kicinski 16923ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16933ff5a4dcSJakub Kicinski map_replace_compar); 16943ff5a4dcSJakub Kicinski 16953ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 16963ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 16973ff5a4dcSJakub Kicinski */ 16983ff5a4dcSJakub Kicinski j = 0; 16993ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 17003ff5a4dcSJakub Kicinski i = 0; 1701f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 17023ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 17033ff5a4dcSJakub Kicinski map_replace[j].idx = i; 17043ff5a4dcSJakub Kicinski break; 17053ff5a4dcSJakub Kicinski } 17063ff5a4dcSJakub Kicinski i++; 17073ff5a4dcSJakub Kicinski } 17083ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 17093ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 17103ff5a4dcSJakub Kicinski goto err_close_obj; 17113ff5a4dcSJakub Kicinski } 17123ff5a4dcSJakub Kicinski j++; 17133ff5a4dcSJakub Kicinski } 17143ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 17153ff5a4dcSJakub Kicinski if (j) 17163ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 17173ff5a4dcSJakub Kicinski map_replace_compar); 17183ff5a4dcSJakub Kicinski 17193ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 17203ff5a4dcSJakub Kicinski j = 0; 17213ff5a4dcSJakub Kicinski idx = 0; 1722f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 17239855c131SChristy Lee if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1724c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1725c8406848SJakub Kicinski 17263ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 17273ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 17283ff5a4dcSJakub Kicinski if (err) { 17293ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 17303ff5a4dcSJakub Kicinski goto err_close_obj; 17313ff5a4dcSJakub Kicinski } 17323ff5a4dcSJakub Kicinski 17333ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 17343ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 17353ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 17363ff5a4dcSJakub Kicinski idx); 17373ff5a4dcSJakub Kicinski goto err_close_obj; 17383ff5a4dcSJakub Kicinski } 17393ff5a4dcSJakub Kicinski } 17403ff5a4dcSJakub Kicinski 17413ff5a4dcSJakub Kicinski idx++; 17423ff5a4dcSJakub Kicinski } 17433ff5a4dcSJakub Kicinski if (j < old_map_fds) { 17443ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 17453ff5a4dcSJakub Kicinski goto err_close_obj; 17463ff5a4dcSJakub Kicinski } 17473ff5a4dcSJakub Kicinski 1748b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1749c8406848SJakub Kicinski if (err) { 1750c8406848SJakub Kicinski p_err("failed to load object file"); 1751c8406848SJakub Kicinski goto err_close_obj; 1752c8406848SJakub Kicinski } 1753c8406848SJakub Kicinski 175477380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 175577380998SStanislav Fomichev if (err) 1756bfee71fbSJakub Kicinski goto err_close_obj; 175749a086c2SRoman Gushchin 175877380998SStanislav Fomichev if (first_prog_only) { 17596f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 176077380998SStanislav Fomichev if (!prog) { 176177380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 176277380998SStanislav Fomichev goto err_close_obj; 176377380998SStanislav Fomichev } 176477380998SStanislav Fomichev 176519526e70SWang Yufen if (auto_attach) 176619526e70SWang Yufen err = auto_attach_program(prog, pinfile); 176719526e70SWang Yufen else 176877380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 176977380998SStanislav Fomichev if (err) { 177077380998SStanislav Fomichev p_err("failed to pin program %s", 1771fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 177277380998SStanislav Fomichev goto err_close_obj; 177377380998SStanislav Fomichev } 177477380998SStanislav Fomichev } else { 177519526e70SWang Yufen if (auto_attach) 177619526e70SWang Yufen err = auto_attach_programs(obj, pinfile); 177719526e70SWang Yufen else 177877380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 177977380998SStanislav Fomichev if (err) { 178077380998SStanislav Fomichev p_err("failed to pin all programs"); 178177380998SStanislav Fomichev goto err_close_obj; 178277380998SStanislav Fomichev } 178377380998SStanislav Fomichev } 178477380998SStanislav Fomichev 17853767a94bSStanislav Fomichev if (pinmaps) { 17863767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 17873767a94bSStanislav Fomichev if (err) { 17883767a94bSStanislav Fomichev p_err("failed to pin all maps"); 17893767a94bSStanislav Fomichev goto err_unpin; 17903767a94bSStanislav Fomichev } 17913767a94bSStanislav Fomichev } 17923767a94bSStanislav Fomichev 179349a086c2SRoman Gushchin if (json_output) 179449a086c2SRoman Gushchin jsonw_null(json_wtr); 179549a086c2SRoman Gushchin 1796bfee71fbSJakub Kicinski bpf_object__close(obj); 17973ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17983ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17993ff5a4dcSJakub Kicinski free(map_replace); 1800bfee71fbSJakub Kicinski 180149a086c2SRoman Gushchin return 0; 1802bfee71fbSJakub Kicinski 18033767a94bSStanislav Fomichev err_unpin: 18043767a94bSStanislav Fomichev if (first_prog_only) 18053767a94bSStanislav Fomichev unlink(pinfile); 18063767a94bSStanislav Fomichev else 18073767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1808bfee71fbSJakub Kicinski err_close_obj: 1809314f14abSStanislav Fomichev if (!legacy_libbpf) { 1810314f14abSStanislav Fomichev p_info("Warning: bpftool is now running in libbpf strict mode and has more stringent requirements about BPF programs.\n" 1811314f14abSStanislav Fomichev "If it used to work for this object file but now doesn't, see --legacy option for more details.\n"); 1812314f14abSStanislav Fomichev } 1813314f14abSStanislav Fomichev 1814bfee71fbSJakub Kicinski bpf_object__close(obj); 18153ff5a4dcSJakub Kicinski err_free_reuse_maps: 18163ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 18173ff5a4dcSJakub Kicinski close(map_replace[i].fd); 18183ff5a4dcSJakub Kicinski free(map_replace); 1819bfee71fbSJakub Kicinski return -1; 182049a086c2SRoman Gushchin } 182149a086c2SRoman Gushchin 1822d510296dSAlexei Starovoitov static int count_open_fds(void) 1823d510296dSAlexei Starovoitov { 1824d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1825d510296dSAlexei Starovoitov struct dirent *de; 1826d510296dSAlexei Starovoitov int cnt = -3; 1827d510296dSAlexei Starovoitov 1828d510296dSAlexei Starovoitov if (!dp) 1829d510296dSAlexei Starovoitov return -1; 1830d510296dSAlexei Starovoitov 1831d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1832d510296dSAlexei Starovoitov cnt++; 1833d510296dSAlexei Starovoitov 1834d510296dSAlexei Starovoitov closedir(dp); 1835d510296dSAlexei Starovoitov return cnt; 1836d510296dSAlexei Starovoitov } 1837d510296dSAlexei Starovoitov 1838d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1839d510296dSAlexei Starovoitov { 1840d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1841d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1842d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1843d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1844d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1845d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1846942df4dcSAlexei Starovoitov char *log_buf = NULL; 1847d510296dSAlexei Starovoitov 1848d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1849d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1850d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1851942df4dcSAlexei Starovoitov if (verifier_logs) { 1852942df4dcSAlexei Starovoitov ctx->log_level = 1 + 2 + 4; 1853d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1854d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1855d510296dSAlexei Starovoitov if (!log_buf) 1856d510296dSAlexei Starovoitov return -ENOMEM; 1857d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1858942df4dcSAlexei Starovoitov } 1859d510296dSAlexei Starovoitov opts.ctx = ctx; 1860d510296dSAlexei Starovoitov opts.data = gen->data; 1861d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1862d510296dSAlexei Starovoitov opts.insns = gen->insns; 1863d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1864d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1865d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1866d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1867942df4dcSAlexei Starovoitov if (err < 0 || verifier_logs) { 1868d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1869942df4dcSAlexei Starovoitov if (fd_delta && err < 0) 1870d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1871d510296dSAlexei Starovoitov fd_delta); 1872d510296dSAlexei Starovoitov } 1873d510296dSAlexei Starovoitov free(log_buf); 1874d510296dSAlexei Starovoitov return err; 1875d510296dSAlexei Starovoitov } 1876d510296dSAlexei Starovoitov 1877d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1878d510296dSAlexei Starovoitov { 1879d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1880d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1881d510296dSAlexei Starovoitov struct bpf_object *obj; 1882d510296dSAlexei Starovoitov const char *file; 1883d510296dSAlexei Starovoitov int err = 0; 1884d510296dSAlexei Starovoitov 1885d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1886d510296dSAlexei Starovoitov return -1; 1887d510296dSAlexei Starovoitov file = GET_ARG(); 1888d510296dSAlexei Starovoitov 1889b59e4ce8SAndrii Nakryiko if (verifier_logs) 1890b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1891b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1892b59e4ce8SAndrii Nakryiko 1893d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1894d510296dSAlexei Starovoitov if (libbpf_get_error(obj)) { 1895d510296dSAlexei Starovoitov p_err("failed to open object file"); 1896d510296dSAlexei Starovoitov goto err_close_obj; 1897d510296dSAlexei Starovoitov } 1898d510296dSAlexei Starovoitov 1899d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1900d510296dSAlexei Starovoitov if (err) 1901d510296dSAlexei Starovoitov goto err_close_obj; 1902d510296dSAlexei Starovoitov 1903b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1904d510296dSAlexei Starovoitov if (err) { 1905d510296dSAlexei Starovoitov p_err("failed to load object file"); 1906d510296dSAlexei Starovoitov goto err_close_obj; 1907d510296dSAlexei Starovoitov } 1908d510296dSAlexei Starovoitov 1909d510296dSAlexei Starovoitov if (verifier_logs) { 1910d510296dSAlexei Starovoitov struct dump_data dd = {}; 1911d510296dSAlexei Starovoitov 1912d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1913d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1914d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1915d510296dSAlexei Starovoitov } 1916d510296dSAlexei Starovoitov err = try_loader(&gen); 1917d510296dSAlexei Starovoitov err_close_obj: 1918d510296dSAlexei Starovoitov bpf_object__close(obj); 1919d510296dSAlexei Starovoitov return err; 1920d510296dSAlexei Starovoitov } 1921d510296dSAlexei Starovoitov 192277380998SStanislav Fomichev static int do_load(int argc, char **argv) 192377380998SStanislav Fomichev { 1924d510296dSAlexei Starovoitov if (use_loader) 1925d510296dSAlexei Starovoitov return do_loader(argc, argv); 192677380998SStanislav Fomichev return load_with_options(argc, argv, true); 192777380998SStanislav Fomichev } 192877380998SStanislav Fomichev 192977380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 193077380998SStanislav Fomichev { 193177380998SStanislav Fomichev return load_with_options(argc, argv, false); 193277380998SStanislav Fomichev } 193377380998SStanislav Fomichev 193447c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 193547c09d6aSSong Liu 193647c09d6aSSong Liu static int do_profile(int argc, char **argv) 193747c09d6aSSong Liu { 193814e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 193947c09d6aSSong Liu return 0; 194047c09d6aSSong Liu } 194147c09d6aSSong Liu 194247c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 194347c09d6aSSong Liu 194447c09d6aSSong Liu #include "profiler.skel.h" 194547c09d6aSSong Liu 194647c09d6aSSong Liu struct profile_metric { 194747c09d6aSSong Liu const char *name; 194847c09d6aSSong Liu struct bpf_perf_event_value val; 194947c09d6aSSong Liu struct perf_event_attr attr; 195047c09d6aSSong Liu bool selected; 195147c09d6aSSong Liu 195247c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 195347c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 195447c09d6aSSong Liu const char *ratio_desc; 195547c09d6aSSong Liu const float ratio_mul; 195647c09d6aSSong Liu } metrics[] = { 195747c09d6aSSong Liu { 195847c09d6aSSong Liu .name = "cycles", 195947c09d6aSSong Liu .attr = { 196047c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 196147c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 196247c09d6aSSong Liu .exclude_user = 1, 196347c09d6aSSong Liu }, 196447c09d6aSSong Liu }, 196547c09d6aSSong Liu { 196647c09d6aSSong Liu .name = "instructions", 196747c09d6aSSong Liu .attr = { 196847c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 196947c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 197047c09d6aSSong Liu .exclude_user = 1, 197147c09d6aSSong Liu }, 197247c09d6aSSong Liu .ratio_metric = 1, 197347c09d6aSSong Liu .ratio_desc = "insns per cycle", 197447c09d6aSSong Liu .ratio_mul = 1.0, 197547c09d6aSSong Liu }, 197647c09d6aSSong Liu { 197747c09d6aSSong Liu .name = "l1d_loads", 197847c09d6aSSong Liu .attr = { 197947c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 198047c09d6aSSong Liu .config = 198147c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 198247c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 198347c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 198447c09d6aSSong Liu .exclude_user = 1, 198547c09d6aSSong Liu }, 198647c09d6aSSong Liu }, 198747c09d6aSSong Liu { 198847c09d6aSSong Liu .name = "llc_misses", 198947c09d6aSSong Liu .attr = { 199047c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 199147c09d6aSSong Liu .config = 199247c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 199347c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 199447c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 199547c09d6aSSong Liu .exclude_user = 1 199647c09d6aSSong Liu }, 199747c09d6aSSong Liu .ratio_metric = 2, 199847c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 199947c09d6aSSong Liu .ratio_mul = 1e6, 200047c09d6aSSong Liu }, 2001450d060eSYonghong Song { 2002450d060eSYonghong Song .name = "itlb_misses", 2003450d060eSYonghong Song .attr = { 2004450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 2005450d060eSYonghong Song .config = 2006450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 2007450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2008450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 2009450d060eSYonghong Song .exclude_user = 1 2010450d060eSYonghong Song }, 2011450d060eSYonghong Song .ratio_metric = 2, 2012450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 2013450d060eSYonghong Song .ratio_mul = 1e6, 2014450d060eSYonghong Song }, 2015450d060eSYonghong Song { 2016450d060eSYonghong Song .name = "dtlb_misses", 2017450d060eSYonghong Song .attr = { 2018450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 2019450d060eSYonghong Song .config = 2020450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 2021450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2022450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 2023450d060eSYonghong Song .exclude_user = 1 2024450d060eSYonghong Song }, 2025450d060eSYonghong Song .ratio_metric = 2, 2026450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 2027450d060eSYonghong Song .ratio_mul = 1e6, 2028450d060eSYonghong Song }, 202947c09d6aSSong Liu }; 203047c09d6aSSong Liu 203147c09d6aSSong Liu static __u64 profile_total_count; 203247c09d6aSSong Liu 203347c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 203447c09d6aSSong Liu 203547c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 203647c09d6aSSong Liu { 203747c09d6aSSong Liu unsigned int metric_cnt; 203847c09d6aSSong Liu int selected_cnt = 0; 203947c09d6aSSong Liu unsigned int i; 204047c09d6aSSong Liu 20415eff8c18SRongguang Wei metric_cnt = ARRAY_SIZE(metrics); 204247c09d6aSSong Liu 204347c09d6aSSong Liu while (argc > 0) { 204447c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 204547c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 204647c09d6aSSong Liu if (!metrics[i].selected) 204747c09d6aSSong Liu selected_cnt++; 204847c09d6aSSong Liu metrics[i].selected = true; 204947c09d6aSSong Liu break; 205047c09d6aSSong Liu } 205147c09d6aSSong Liu } 205247c09d6aSSong Liu if (i == metric_cnt) { 205347c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 205447c09d6aSSong Liu return -1; 205547c09d6aSSong Liu } 205647c09d6aSSong Liu NEXT_ARG(); 205747c09d6aSSong Liu } 205847c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 205947c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 206047c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 206147c09d6aSSong Liu return -1; 206247c09d6aSSong Liu } 206347c09d6aSSong Liu return selected_cnt; 206447c09d6aSSong Liu } 206547c09d6aSSong Liu 206647c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 206747c09d6aSSong Liu { 206847c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 206947c09d6aSSong Liu int reading_map_fd, count_map_fd; 207047c09d6aSSong Liu __u64 counts[num_cpu]; 207147c09d6aSSong Liu __u32 key = 0; 207247c09d6aSSong Liu int err; 207347c09d6aSSong Liu 207447c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 207547c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 207647c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 207747c09d6aSSong Liu p_err("failed to get fd for map"); 207847c09d6aSSong Liu return; 207947c09d6aSSong Liu } 208047c09d6aSSong Liu 208147c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 208247c09d6aSSong Liu if (err) { 208347c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 208447c09d6aSSong Liu return; 208547c09d6aSSong Liu } 208647c09d6aSSong Liu 208747c09d6aSSong Liu profile_total_count = 0; 208847c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 208947c09d6aSSong Liu profile_total_count += counts[cpu]; 209047c09d6aSSong Liu 209147c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 209247c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 209347c09d6aSSong Liu 209447c09d6aSSong Liu if (!metrics[m].selected) 209547c09d6aSSong Liu continue; 209647c09d6aSSong Liu 209747c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 209847c09d6aSSong Liu if (err) { 209947c09d6aSSong Liu p_err("failed to read reading_map: %s", 210047c09d6aSSong Liu strerror(errno)); 210147c09d6aSSong Liu return; 210247c09d6aSSong Liu } 210347c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 210447c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 210547c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 210647c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 210747c09d6aSSong Liu } 210847c09d6aSSong Liu key++; 210947c09d6aSSong Liu } 211047c09d6aSSong Liu } 211147c09d6aSSong Liu 211247c09d6aSSong Liu static void profile_print_readings_json(void) 211347c09d6aSSong Liu { 211447c09d6aSSong Liu __u32 m; 211547c09d6aSSong Liu 211647c09d6aSSong Liu jsonw_start_array(json_wtr); 211747c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 211847c09d6aSSong Liu if (!metrics[m].selected) 211947c09d6aSSong Liu continue; 212047c09d6aSSong Liu jsonw_start_object(json_wtr); 212147c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 212247c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 212347c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 212447c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 212547c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 212647c09d6aSSong Liu 212747c09d6aSSong Liu jsonw_end_object(json_wtr); 212847c09d6aSSong Liu } 212947c09d6aSSong Liu jsonw_end_array(json_wtr); 213047c09d6aSSong Liu } 213147c09d6aSSong Liu 213247c09d6aSSong Liu static void profile_print_readings_plain(void) 213347c09d6aSSong Liu { 213447c09d6aSSong Liu __u32 m; 213547c09d6aSSong Liu 213647c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 213747c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 213847c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 213947c09d6aSSong Liu int r; 214047c09d6aSSong Liu 214147c09d6aSSong Liu if (!metrics[m].selected) 214247c09d6aSSong Liu continue; 214347c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 214447c09d6aSSong Liu 214547c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 214647c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 214747c09d6aSSong Liu metrics[r].val.counter > 0) { 214847c09d6aSSong Liu printf("# %8.2f %-30s", 214947c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 215047c09d6aSSong Liu metrics[r].val.counter, 215147c09d6aSSong Liu metrics[m].ratio_desc); 215247c09d6aSSong Liu } else { 215347c09d6aSSong Liu printf("%-41s", ""); 215447c09d6aSSong Liu } 215547c09d6aSSong Liu 215647c09d6aSSong Liu if (val->enabled > val->running) 215747c09d6aSSong Liu printf("(%4.2f%%)", 215847c09d6aSSong Liu val->running * 100.0 / val->enabled); 215947c09d6aSSong Liu printf("\n"); 216047c09d6aSSong Liu } 216147c09d6aSSong Liu } 216247c09d6aSSong Liu 216347c09d6aSSong Liu static void profile_print_readings(void) 216447c09d6aSSong Liu { 216547c09d6aSSong Liu if (json_output) 216647c09d6aSSong Liu profile_print_readings_json(); 216747c09d6aSSong Liu else 216847c09d6aSSong Liu profile_print_readings_plain(); 216947c09d6aSSong Liu } 217047c09d6aSSong Liu 217147c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 217247c09d6aSSong Liu { 2173c59765cfSDave Marchevsky struct bpf_func_info func_info; 2174c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2175c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 217647c09d6aSSong Liu const struct btf_type *t; 2177c59765cfSDave Marchevsky __u32 func_info_rec_size; 2178369e955bSQuentin Monnet struct btf *btf = NULL; 217947c09d6aSSong Liu char *name = NULL; 2180c59765cfSDave Marchevsky int err; 218147c09d6aSSong Liu 2182c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2183c59765cfSDave Marchevsky if (err) { 2184c59765cfSDave Marchevsky p_err("failed to bpf_obj_get_info_by_fd for prog FD %d", tgt_fd); 2185c59765cfSDave Marchevsky goto out; 218647c09d6aSSong Liu } 218747c09d6aSSong Liu 2188c59765cfSDave Marchevsky if (info.btf_id == 0) { 218947c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 219047c09d6aSSong Liu goto out; 219147c09d6aSSong Liu } 219247c09d6aSSong Liu 2193c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2194c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 2195c59765cfSDave Marchevsky p_err("bpf_obj_get_info_by_fd for prog FD %d found 0 func_info", tgt_fd); 2196c59765cfSDave Marchevsky goto out; 2197c59765cfSDave Marchevsky } 2198c59765cfSDave Marchevsky 2199c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2200c59765cfSDave Marchevsky info.nr_func_info = 1; 2201c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2202c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2203c59765cfSDave Marchevsky 2204c59765cfSDave Marchevsky err = bpf_obj_get_info_by_fd(tgt_fd, &info, &info_len); 2205c59765cfSDave Marchevsky if (err) { 2206c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2207c59765cfSDave Marchevsky goto out; 2208c59765cfSDave Marchevsky } 2209c59765cfSDave Marchevsky 2210c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 221186f4b7f2SQuentin Monnet if (libbpf_get_error(btf)) { 221286f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 221386f4b7f2SQuentin Monnet goto out; 221486f4b7f2SQuentin Monnet } 221586f4b7f2SQuentin Monnet 2216c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 221747c09d6aSSong Liu if (!t) { 221847c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2219c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 222047c09d6aSSong Liu goto out; 222147c09d6aSSong Liu } 222247c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 222347c09d6aSSong Liu out: 2224369e955bSQuentin Monnet btf__free(btf); 222547c09d6aSSong Liu return name; 222647c09d6aSSong Liu } 222747c09d6aSSong Liu 222847c09d6aSSong Liu static struct profiler_bpf *profile_obj; 222947c09d6aSSong Liu static int profile_tgt_fd = -1; 223047c09d6aSSong Liu static char *profile_tgt_name; 223147c09d6aSSong Liu static int *profile_perf_events; 223247c09d6aSSong Liu static int profile_perf_event_cnt; 223347c09d6aSSong Liu 223447c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 223547c09d6aSSong Liu { 223647c09d6aSSong Liu int i; 223747c09d6aSSong Liu 223847c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 223947c09d6aSSong Liu close(profile_perf_events[i]); 224047c09d6aSSong Liu 224147c09d6aSSong Liu free(profile_perf_events); 224247c09d6aSSong Liu profile_perf_event_cnt = 0; 224347c09d6aSSong Liu } 224447c09d6aSSong Liu 224547c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 224647c09d6aSSong Liu { 224747c09d6aSSong Liu unsigned int cpu, m; 224847c09d6aSSong Liu int map_fd, pmu_fd; 224947c09d6aSSong Liu 225047c09d6aSSong Liu profile_perf_events = calloc( 225147c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 225247c09d6aSSong Liu if (!profile_perf_events) { 225347c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 225447c09d6aSSong Liu strerror(errno)); 225547c09d6aSSong Liu return -1; 225647c09d6aSSong Liu } 225747c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 225847c09d6aSSong Liu if (map_fd < 0) { 225947c09d6aSSong Liu p_err("failed to get fd for events map"); 226047c09d6aSSong Liu return -1; 226147c09d6aSSong Liu } 226247c09d6aSSong Liu 226347c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 226447c09d6aSSong Liu if (!metrics[m].selected) 226547c09d6aSSong Liu continue; 226647c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 226747c09d6aSSong Liu pmu_fd = syscall(__NR_perf_event_open, &metrics[m].attr, 226847c09d6aSSong Liu -1/*pid*/, cpu, -1/*group_fd*/, 0); 226947c09d6aSSong Liu if (pmu_fd < 0 || 227047c09d6aSSong Liu bpf_map_update_elem(map_fd, &profile_perf_event_cnt, 227147c09d6aSSong Liu &pmu_fd, BPF_ANY) || 227247c09d6aSSong Liu ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 227347c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 227447c09d6aSSong Liu metrics[m].name, cpu); 227547c09d6aSSong Liu return -1; 227647c09d6aSSong Liu } 227747c09d6aSSong Liu profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 227847c09d6aSSong Liu } 227947c09d6aSSong Liu } 228047c09d6aSSong Liu return 0; 228147c09d6aSSong Liu } 228247c09d6aSSong Liu 228347c09d6aSSong Liu static void profile_print_and_cleanup(void) 228447c09d6aSSong Liu { 228547c09d6aSSong Liu profile_close_perf_events(profile_obj); 228647c09d6aSSong Liu profile_read_values(profile_obj); 228747c09d6aSSong Liu profile_print_readings(); 228847c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 228947c09d6aSSong Liu 229047c09d6aSSong Liu close(profile_tgt_fd); 229147c09d6aSSong Liu free(profile_tgt_name); 229247c09d6aSSong Liu } 229347c09d6aSSong Liu 229447c09d6aSSong Liu static void int_exit(int signo) 229547c09d6aSSong Liu { 229647c09d6aSSong Liu profile_print_and_cleanup(); 229747c09d6aSSong Liu exit(0); 229847c09d6aSSong Liu } 229947c09d6aSSong Liu 230047c09d6aSSong Liu static int do_profile(int argc, char **argv) 230147c09d6aSSong Liu { 230247c09d6aSSong Liu int num_metric, num_cpu, err = -1; 230347c09d6aSSong Liu struct bpf_program *prog; 230447c09d6aSSong Liu unsigned long duration; 230547c09d6aSSong Liu char *endptr; 230647c09d6aSSong Liu 230747c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 230847c09d6aSSong Liu if (!REQ_ARGS(3)) 230947c09d6aSSong Liu return -EINVAL; 231047c09d6aSSong Liu 231147c09d6aSSong Liu /* parse target fd */ 231247c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 231347c09d6aSSong Liu if (profile_tgt_fd < 0) { 231447c09d6aSSong Liu p_err("failed to parse fd"); 231547c09d6aSSong Liu return -1; 231647c09d6aSSong Liu } 231747c09d6aSSong Liu 231847c09d6aSSong Liu /* parse profiling optional duration */ 231947c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 232047c09d6aSSong Liu NEXT_ARG(); 232147c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 232247c09d6aSSong Liu if (*endptr) 232347c09d6aSSong Liu usage(); 232447c09d6aSSong Liu NEXT_ARG(); 232547c09d6aSSong Liu } else { 232647c09d6aSSong Liu duration = UINT_MAX; 232747c09d6aSSong Liu } 232847c09d6aSSong Liu 232947c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 233047c09d6aSSong Liu if (num_metric <= 0) 233147c09d6aSSong Liu goto out; 233247c09d6aSSong Liu 233347c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 233447c09d6aSSong Liu if (num_cpu <= 0) { 233547c09d6aSSong Liu p_err("failed to identify number of CPUs"); 233647c09d6aSSong Liu goto out; 233747c09d6aSSong Liu } 233847c09d6aSSong Liu 233947c09d6aSSong Liu profile_obj = profiler_bpf__open(); 234047c09d6aSSong Liu if (!profile_obj) { 234147c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 234247c09d6aSSong Liu goto out; 234347c09d6aSSong Liu } 234447c09d6aSSong Liu 234547c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 234647c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 234747c09d6aSSong Liu 234847c09d6aSSong Liu /* adjust map sizes */ 234939748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu); 235039748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric); 235139748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric); 235239748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.counts, 1); 235347c09d6aSSong Liu 235447c09d6aSSong Liu /* change target name */ 235547c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 235647c09d6aSSong Liu if (!profile_tgt_name) 235747c09d6aSSong Liu goto out; 235847c09d6aSSong Liu 235947c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 236047c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 236147c09d6aSSong Liu profile_tgt_name); 236247c09d6aSSong Liu if (err) { 236347c09d6aSSong Liu p_err("failed to set attach target\n"); 236447c09d6aSSong Liu goto out; 236547c09d6aSSong Liu } 236647c09d6aSSong Liu } 236747c09d6aSSong Liu 23686b4384ffSQuentin Monnet set_max_rlimit(); 236947c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 237047c09d6aSSong Liu if (err) { 237147c09d6aSSong Liu p_err("failed to load profile_obj"); 237247c09d6aSSong Liu goto out; 237347c09d6aSSong Liu } 237447c09d6aSSong Liu 237547c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 237647c09d6aSSong Liu if (err) 237747c09d6aSSong Liu goto out; 237847c09d6aSSong Liu 237947c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 238047c09d6aSSong Liu if (err) { 238147c09d6aSSong Liu p_err("failed to attach profile_obj"); 238247c09d6aSSong Liu goto out; 238347c09d6aSSong Liu } 238447c09d6aSSong Liu signal(SIGINT, int_exit); 238547c09d6aSSong Liu 238647c09d6aSSong Liu sleep(duration); 238747c09d6aSSong Liu profile_print_and_cleanup(); 238847c09d6aSSong Liu return 0; 238947c09d6aSSong Liu 239047c09d6aSSong Liu out: 239147c09d6aSSong Liu profile_close_perf_events(profile_obj); 239247c09d6aSSong Liu if (profile_obj) 239347c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 239447c09d6aSSong Liu close(profile_tgt_fd); 239547c09d6aSSong Liu free(profile_tgt_name); 239647c09d6aSSong Liu return err; 239747c09d6aSSong Liu } 239847c09d6aSSong Liu 239947c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 240047c09d6aSSong Liu 240171bb428fSJakub Kicinski static int do_help(int argc, char **argv) 240271bb428fSJakub Kicinski { 2403004b45c0SQuentin Monnet if (json_output) { 2404004b45c0SQuentin Monnet jsonw_null(json_wtr); 2405004b45c0SQuentin Monnet return 0; 2406004b45c0SQuentin Monnet } 2407004b45c0SQuentin Monnet 240871bb428fSJakub Kicinski fprintf(stderr, 240990040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 241090040351SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 241190040351SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | opcodes | linum }]\n" 241290040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 241390040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 241477380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 24153767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 24163767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 241719526e70SWang Yufen " [autoattach]\n" 241890040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 241990040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 242090040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2421ba95c745SQuentin Monnet " data_in FILE \\\n" 2422ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2423ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2424ba95c745SQuentin Monnet " [repeat N]\n" 242590040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 242690040351SQuentin Monnet " %1$s %2$s tracelog\n" 242790040351SQuentin Monnet " %1$s %2$s help\n" 242871bb428fSJakub Kicinski "\n" 24293ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 243071bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 243149f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 243249f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 243349f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 243449f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2435f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 243649f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 243749f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 243805ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 243905ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 244005ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2441a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 244293a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 24431ba5ad36SDaniel Müller " ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n" 24441ba5ad36SDaniel Müller " sk_skb_stream_parser | flow_dissector }\n" 2445450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2446c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 24478cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 24488cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 244971bb428fSJakub Kicinski "", 245090040351SQuentin Monnet bin_name, argv[-2]); 245171bb428fSJakub Kicinski 245271bb428fSJakub Kicinski return 0; 245371bb428fSJakub Kicinski } 245471bb428fSJakub Kicinski 245571bb428fSJakub Kicinski static const struct cmd cmds[] = { 245671bb428fSJakub Kicinski { "show", do_show }, 24576ebe6dbdSJakub Kicinski { "list", do_show }, 24589f606179SQuentin Monnet { "help", do_help }, 245971bb428fSJakub Kicinski { "dump", do_dump }, 246071bb428fSJakub Kicinski { "pin", do_pin }, 246149a086c2SRoman Gushchin { "load", do_load }, 246277380998SStanislav Fomichev { "loadall", do_loadall }, 2463b7d3826cSJohn Fastabend { "attach", do_attach }, 2464b7d3826cSJohn Fastabend { "detach", do_detach }, 246530da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2466ba95c745SQuentin Monnet { "run", do_run }, 246747c09d6aSSong Liu { "profile", do_profile }, 246871bb428fSJakub Kicinski { 0 } 246971bb428fSJakub Kicinski }; 247071bb428fSJakub Kicinski 247171bb428fSJakub Kicinski int do_prog(int argc, char **argv) 247271bb428fSJakub Kicinski { 247371bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 247471bb428fSJakub Kicinski } 2475