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 201*38f0408eSIlya Leoshkevich err = bpf_prog_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); 234*38f0408eSIlya Leoshkevich ret = bpf_prog_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 251*38f0408eSIlya Leoshkevich ret = bpf_prog_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); 262*38f0408eSIlya Leoshkevich ret = bpf_map_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); 325d1313e01SSahid Orentino Ferdjaoui if (!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); 489c302378bSEduard Zingerman hashmap__for_each_key_entry(prog_table, entry, info->id) 490c302378bSEduard Zingerman jsonw_string(json_wtr, entry->pvalue); 4914990f1f4SPrashant Bhole jsonw_end_array(json_wtr); 4924990f1f4SPrashant Bhole } 4934990f1f4SPrashant Bhole 494d6699f8eSQuentin Monnet emit_obj_refs_json(refs_table, info->id, json_wtr); 495d53dee3fSAndrii Nakryiko 496aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 497aff52e68SYiFei Zhu 498743cc665SQuentin Monnet jsonw_end_object(json_wtr); 499743cc665SQuentin Monnet } 500743cc665SQuentin Monnet 501b662000aSRaman Shukhau static void print_prog_header_plain(struct bpf_prog_info *info, int fd) 502743cc665SQuentin Monnet { 503b700eeb4SDaniel Müller const char *prog_type_str; 504b662000aSRaman Shukhau char prog_name[MAX_PROG_FULL_NAME]; 505b662000aSRaman Shukhau 506743cc665SQuentin Monnet printf("%u: ", info->id); 507b700eeb4SDaniel Müller prog_type_str = libbpf_bpf_prog_type_str(info->type); 508b700eeb4SDaniel Müller if (prog_type_str) 509b700eeb4SDaniel Müller printf("%s ", prog_type_str); 510743cc665SQuentin Monnet else 511743cc665SQuentin Monnet printf("type %u ", info->type); 512743cc665SQuentin Monnet 513b662000aSRaman Shukhau if (*info->name) { 514b662000aSRaman Shukhau get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 515b662000aSRaman Shukhau printf("name %s ", prog_name); 516b662000aSRaman Shukhau } 517743cc665SQuentin Monnet 518743cc665SQuentin Monnet printf("tag "); 519743cc665SQuentin Monnet fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 52052262210SJakub Kicinski print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 5219b984a20SJiri Olsa printf("%s", info->gpl_compatible ? " gpl" : ""); 52288ad472bSAlexei Starovoitov if (info->run_time_ns) 52388ad472bSAlexei Starovoitov printf(" run_time_ns %lld run_cnt %lld", 52488ad472bSAlexei Starovoitov info->run_time_ns, info->run_cnt); 5259ed9e9baSAlexei Starovoitov if (info->recursion_misses) 5269ed9e9baSAlexei Starovoitov printf(" recursion_misses %lld", info->recursion_misses); 527743cc665SQuentin Monnet printf("\n"); 528ec202509SPaul Chaignon } 529ec202509SPaul Chaignon 530ec202509SPaul Chaignon static void print_prog_plain(struct bpf_prog_info *info, int fd) 531ec202509SPaul Chaignon { 532ec202509SPaul Chaignon char *memlock; 533ec202509SPaul Chaignon 534b662000aSRaman Shukhau print_prog_header_plain(info, fd); 535743cc665SQuentin Monnet 536743cc665SQuentin Monnet if (info->load_time) { 537743cc665SQuentin Monnet char buf[32]; 538743cc665SQuentin Monnet 539743cc665SQuentin Monnet print_boot_time(info->load_time, buf, sizeof(buf)); 540743cc665SQuentin Monnet 541743cc665SQuentin Monnet /* Piggy back on load_time, since 0 uid is a valid one */ 542743cc665SQuentin Monnet printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 543743cc665SQuentin Monnet } 544743cc665SQuentin Monnet 545743cc665SQuentin Monnet printf("\txlated %uB", info->xlated_prog_len); 546743cc665SQuentin Monnet 547743cc665SQuentin Monnet if (info->jited_prog_len) 548743cc665SQuentin Monnet printf(" jited %uB", info->jited_prog_len); 54971bb428fSJakub Kicinski else 55071bb428fSJakub Kicinski printf(" not jited"); 55171bb428fSJakub Kicinski 55271bb428fSJakub Kicinski memlock = get_fdinfo(fd, "memlock"); 55371bb428fSJakub Kicinski if (memlock) 55471bb428fSJakub Kicinski printf(" memlock %sB", memlock); 55571bb428fSJakub Kicinski free(memlock); 55671bb428fSJakub Kicinski 557743cc665SQuentin Monnet if (info->nr_map_ids) 558743cc665SQuentin Monnet show_prog_maps(fd, info->nr_map_ids); 55971bb428fSJakub Kicinski 5608f184732SQuentin Monnet if (!hashmap__empty(prog_table)) { 5618f184732SQuentin Monnet struct hashmap_entry *entry; 5624990f1f4SPrashant Bhole 563c302378bSEduard Zingerman hashmap__for_each_key_entry(prog_table, entry, info->id) 564c302378bSEduard Zingerman printf("\n\tpinned %s", (char *)entry->pvalue); 5654990f1f4SPrashant Bhole } 5664990f1f4SPrashant Bhole 567569b0c77SPrashant Bhole if (info->btf_id) 568031ebc1aSQuentin Monnet printf("\n\tbtf_id %d", info->btf_id); 569569b0c77SPrashant Bhole 570d6699f8eSQuentin Monnet emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 571d53dee3fSAndrii Nakryiko 57271bb428fSJakub Kicinski printf("\n"); 573aff52e68SYiFei Zhu 574aff52e68SYiFei Zhu show_prog_metadata(fd, info->nr_map_ids); 575743cc665SQuentin Monnet } 576743cc665SQuentin Monnet 577743cc665SQuentin Monnet static int show_prog(int fd) 578743cc665SQuentin Monnet { 579743cc665SQuentin Monnet struct bpf_prog_info info = {}; 580743cc665SQuentin Monnet __u32 len = sizeof(info); 581743cc665SQuentin Monnet int err; 582743cc665SQuentin Monnet 583*38f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fd, &info, &len); 584743cc665SQuentin Monnet if (err) { 5859a5ab8bfSQuentin Monnet p_err("can't get prog info: %s", strerror(errno)); 586743cc665SQuentin Monnet return -1; 587743cc665SQuentin Monnet } 588743cc665SQuentin Monnet 589743cc665SQuentin Monnet if (json_output) 590743cc665SQuentin Monnet print_prog_json(&info, fd); 591743cc665SQuentin Monnet else 592743cc665SQuentin Monnet print_prog_plain(&info, fd); 59371bb428fSJakub Kicinski 59471bb428fSJakub Kicinski return 0; 59571bb428fSJakub Kicinski } 59671bb428fSJakub Kicinski 597ec202509SPaul Chaignon static int do_show_subset(int argc, char **argv) 598ec202509SPaul Chaignon { 599ec202509SPaul Chaignon int *fds = NULL; 600ec202509SPaul Chaignon int nb_fds, i; 601ec202509SPaul Chaignon int err = -1; 602ec202509SPaul Chaignon 603ec202509SPaul Chaignon fds = malloc(sizeof(int)); 604ec202509SPaul Chaignon if (!fds) { 605ec202509SPaul Chaignon p_err("mem alloc failed"); 606ec202509SPaul Chaignon return -1; 607ec202509SPaul Chaignon } 608ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 609ec202509SPaul Chaignon if (nb_fds < 1) 610ec202509SPaul Chaignon goto exit_free; 611ec202509SPaul Chaignon 612ec202509SPaul Chaignon if (json_output && nb_fds > 1) 613ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 614ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 615ec202509SPaul Chaignon err = show_prog(fds[i]); 616ec202509SPaul Chaignon if (err) { 617ec202509SPaul Chaignon for (; i < nb_fds; i++) 618ec202509SPaul Chaignon close(fds[i]); 619ec202509SPaul Chaignon break; 620ec202509SPaul Chaignon } 621ec202509SPaul Chaignon close(fds[i]); 622ec202509SPaul Chaignon } 623ec202509SPaul Chaignon if (json_output && nb_fds > 1) 624ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 625ec202509SPaul Chaignon 626ec202509SPaul Chaignon exit_free: 627ec202509SPaul Chaignon free(fds); 628ec202509SPaul Chaignon return err; 629ec202509SPaul Chaignon } 630ec202509SPaul Chaignon 63171bb428fSJakub Kicinski static int do_show(int argc, char **argv) 632743cc665SQuentin Monnet { 633743cc665SQuentin Monnet __u32 id = 0; 63471bb428fSJakub Kicinski int err; 63571bb428fSJakub Kicinski int fd; 63671bb428fSJakub Kicinski 63746241271SQuentin Monnet if (show_pinned) { 6388f184732SQuentin Monnet prog_table = hashmap__new(hash_fn_for_key_as_id, 6398f184732SQuentin Monnet equal_fn_for_key_as_id, NULL); 640622a5b58SMauricio Vásquez if (IS_ERR(prog_table)) { 6418f184732SQuentin Monnet p_err("failed to create hashmap for pinned paths"); 6428f184732SQuentin Monnet return -1; 6438f184732SQuentin Monnet } 6448f184732SQuentin Monnet build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 64546241271SQuentin Monnet } 646d53dee3fSAndrii Nakryiko build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 6474990f1f4SPrashant Bhole 648ec202509SPaul Chaignon if (argc == 2) 649ec202509SPaul Chaignon return do_show_subset(argc, argv); 65071bb428fSJakub Kicinski 65171bb428fSJakub Kicinski if (argc) 65271bb428fSJakub Kicinski return BAD_ARG(); 65371bb428fSJakub Kicinski 654743cc665SQuentin Monnet if (json_output) 655743cc665SQuentin Monnet jsonw_start_array(json_wtr); 65671bb428fSJakub Kicinski while (true) { 65771bb428fSJakub Kicinski err = bpf_prog_get_next_id(id, &id); 65871bb428fSJakub Kicinski if (err) { 6591739c26dSQuentin Monnet if (errno == ENOENT) { 6601739c26dSQuentin Monnet err = 0; 66171bb428fSJakub Kicinski break; 6621739c26dSQuentin Monnet } 6639a5ab8bfSQuentin Monnet p_err("can't get next program: %s%s", strerror(errno), 6649a5ab8bfSQuentin Monnet errno == EINVAL ? " -- kernel too old?" : ""); 665743cc665SQuentin Monnet err = -1; 666743cc665SQuentin Monnet break; 66771bb428fSJakub Kicinski } 66871bb428fSJakub Kicinski 66971bb428fSJakub Kicinski fd = bpf_prog_get_fd_by_id(id); 67071bb428fSJakub Kicinski if (fd < 0) { 6718207c6ddSJakub Kicinski if (errno == ENOENT) 6728207c6ddSJakub Kicinski continue; 6739a5ab8bfSQuentin Monnet p_err("can't get prog by id (%u): %s", 67471bb428fSJakub Kicinski id, strerror(errno)); 675743cc665SQuentin Monnet err = -1; 676743cc665SQuentin Monnet break; 67771bb428fSJakub Kicinski } 67871bb428fSJakub Kicinski 67971bb428fSJakub Kicinski err = show_prog(fd); 68071bb428fSJakub Kicinski close(fd); 68171bb428fSJakub Kicinski if (err) 682743cc665SQuentin Monnet break; 68371bb428fSJakub Kicinski } 68471bb428fSJakub Kicinski 685743cc665SQuentin Monnet if (json_output) 686743cc665SQuentin Monnet jsonw_end_array(json_wtr); 687743cc665SQuentin Monnet 688d6699f8eSQuentin Monnet delete_obj_refs_table(refs_table); 689d53dee3fSAndrii Nakryiko 69046241271SQuentin Monnet if (show_pinned) 6918f184732SQuentin Monnet delete_pinned_obj_table(prog_table); 69246241271SQuentin Monnet 693743cc665SQuentin Monnet return err; 69471bb428fSJakub Kicinski } 69571bb428fSJakub Kicinski 696ec202509SPaul Chaignon static int 697ec202509SPaul Chaignon prog_dump(struct bpf_prog_info *info, enum dump_mode mode, 698ec202509SPaul Chaignon char *filepath, bool opcodes, bool visual, bool linum) 69971bb428fSJakub Kicinski { 700b053b439SMartin KaFai Lau struct bpf_prog_linfo *prog_linfo = NULL; 7013ddeac67SJakub Kicinski const char *disasm_opt = NULL; 7027105e828SDaniel Borkmann struct dump_data dd = {}; 703cae73f23SSong Liu void *func_info = NULL; 704254471e5SYonghong Song struct btf *btf = NULL; 705254471e5SYonghong Song char func_sig[1024]; 70671bb428fSJakub Kicinski unsigned char *buf; 707cae73f23SSong Liu __u32 member_len; 708ebbd7f64SQuentin Monnet int fd, err = -1; 70971bb428fSJakub Kicinski ssize_t n; 71071bb428fSJakub Kicinski 711cae73f23SSong Liu if (mode == DUMP_JITED) { 7125b79bcdfSToke Høiland-Jørgensen if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 7139a5ab8bfSQuentin Monnet p_info("no instructions returned"); 714ec202509SPaul Chaignon return -1; 715f84192eeSSandipan Das } 71609f44b75SAndrii Nakryiko buf = u64_to_ptr(info->jited_prog_insns); 717cae73f23SSong Liu member_len = info->jited_prog_len; 718cae73f23SSong Liu } else { /* DUMP_XLATED */ 719d95f1e8bSToke Høiland-Jørgensen if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 7207105e828SDaniel Borkmann p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 721ec202509SPaul Chaignon return -1; 7227105e828SDaniel Borkmann } 72309f44b75SAndrii Nakryiko buf = u64_to_ptr(info->xlated_prog_insns); 724cae73f23SSong Liu member_len = info->xlated_prog_len; 725cae73f23SSong Liu } 7267105e828SDaniel Borkmann 72786f4b7f2SQuentin Monnet if (info->btf_id) { 72886f4b7f2SQuentin Monnet btf = btf__load_from_kernel_by_id(info->btf_id); 729d1313e01SSahid Orentino Ferdjaoui if (!btf) { 730254471e5SYonghong Song p_err("failed to get btf"); 731ec202509SPaul Chaignon return -1; 732254471e5SYonghong Song } 73386f4b7f2SQuentin Monnet } 734254471e5SYonghong Song 73509f44b75SAndrii Nakryiko func_info = u64_to_ptr(info->func_info); 736cae73f23SSong Liu 737cae73f23SSong Liu if (info->nr_line_info) { 738cae73f23SSong Liu prog_linfo = bpf_prog_linfo__new(info); 739b053b439SMartin KaFai Lau if (!prog_linfo) 74010a5ce98SMartin KaFai Lau p_info("error in processing bpf_line_info. continue without it."); 741b053b439SMartin KaFai Lau } 742b053b439SMartin KaFai Lau 74371bb428fSJakub Kicinski if (filepath) { 74471bb428fSJakub Kicinski fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 74571bb428fSJakub Kicinski if (fd < 0) { 7469a5ab8bfSQuentin Monnet p_err("can't open file %s: %s", filepath, 74771bb428fSJakub Kicinski strerror(errno)); 748ebbd7f64SQuentin Monnet goto exit_free; 74971bb428fSJakub Kicinski } 75071bb428fSJakub Kicinski 751cae73f23SSong Liu n = write(fd, buf, member_len); 75271bb428fSJakub Kicinski close(fd); 75309f44b75SAndrii Nakryiko if (n != (ssize_t)member_len) { 7549a5ab8bfSQuentin Monnet p_err("error writing output file: %s", 75571bb428fSJakub Kicinski n < 0 ? strerror(errno) : "short write"); 756ebbd7f64SQuentin Monnet goto exit_free; 75771bb428fSJakub Kicinski } 75852c84d36SQuentin Monnet 75952c84d36SQuentin Monnet if (json_output) 76052c84d36SQuentin Monnet jsonw_null(json_wtr); 761cae73f23SSong Liu } else if (mode == DUMP_JITED) { 762e6593596SJiong Wang const char *name = NULL; 763e6593596SJiong Wang 764cae73f23SSong Liu if (info->ifindex) { 765ce4f6608SQuentin Monnet name = ifindex_to_arch(info->ifindex, info->netns_dev, 766ce4f6608SQuentin Monnet info->netns_ino, &disasm_opt); 767e6593596SJiong Wang if (!name) 768ebbd7f64SQuentin Monnet goto exit_free; 769e6593596SJiong Wang } 770e6593596SJiong Wang 771cae73f23SSong Liu if (info->nr_jited_func_lens && info->jited_func_lens) { 772f7f62c71SSandipan Das struct kernel_sym *sym = NULL; 773254471e5SYonghong Song struct bpf_func_info *record; 774f7f62c71SSandipan Das char sym_name[SYM_MAX_NAME]; 775f7f62c71SSandipan Das unsigned char *img = buf; 776f7f62c71SSandipan Das __u64 *ksyms = NULL; 777f7f62c71SSandipan Das __u32 *lens; 778f7f62c71SSandipan Das __u32 i; 779cae73f23SSong Liu if (info->nr_jited_ksyms) { 780f7f62c71SSandipan Das kernel_syms_load(&dd); 78109f44b75SAndrii Nakryiko ksyms = u64_to_ptr(info->jited_ksyms); 782f7f62c71SSandipan Das } 783f7f62c71SSandipan Das 784f7f62c71SSandipan Das if (json_output) 785f7f62c71SSandipan Das jsonw_start_array(json_wtr); 786f7f62c71SSandipan Das 78709f44b75SAndrii Nakryiko lens = u64_to_ptr(info->jited_func_lens); 788cae73f23SSong Liu for (i = 0; i < info->nr_jited_func_lens; i++) { 789f7f62c71SSandipan Das if (ksyms) { 790f7f62c71SSandipan Das sym = kernel_syms_search(&dd, ksyms[i]); 791f7f62c71SSandipan Das if (sym) 792f7f62c71SSandipan Das sprintf(sym_name, "%s", sym->name); 793f7f62c71SSandipan Das else 794f7f62c71SSandipan Das sprintf(sym_name, "0x%016llx", ksyms[i]); 795f7f62c71SSandipan Das } else { 796f7f62c71SSandipan Das strcpy(sym_name, "unknown"); 797f7f62c71SSandipan Das } 798f7f62c71SSandipan Das 799254471e5SYonghong Song if (func_info) { 800cae73f23SSong Liu record = func_info + i * info->func_info_rec_size; 801254471e5SYonghong Song btf_dumper_type_only(btf, record->type_id, 802254471e5SYonghong Song func_sig, 803254471e5SYonghong Song sizeof(func_sig)); 804254471e5SYonghong Song } 805254471e5SYonghong Song 806f7f62c71SSandipan Das if (json_output) { 807f7f62c71SSandipan Das jsonw_start_object(json_wtr); 808254471e5SYonghong Song if (func_info && func_sig[0] != '\0') { 809254471e5SYonghong Song jsonw_name(json_wtr, "proto"); 810254471e5SYonghong Song jsonw_string(json_wtr, func_sig); 811254471e5SYonghong Song } 812f7f62c71SSandipan Das jsonw_name(json_wtr, "name"); 813f7f62c71SSandipan Das jsonw_string(json_wtr, sym_name); 814f7f62c71SSandipan Das jsonw_name(json_wtr, "insns"); 815f7f62c71SSandipan Das } else { 816254471e5SYonghong Song if (func_info && func_sig[0] != '\0') 817254471e5SYonghong Song printf("%s:\n", func_sig); 818f7f62c71SSandipan Das printf("%s:\n", sym_name); 819f7f62c71SSandipan Das } 820f7f62c71SSandipan Das 82155b4de58SQuentin Monnet if (disasm_print_insn(img, lens[i], opcodes, 822b053b439SMartin KaFai Lau name, disasm_opt, btf, 823b053b439SMartin KaFai Lau prog_linfo, ksyms[i], i, 82455b4de58SQuentin Monnet linum)) 82555b4de58SQuentin Monnet goto exit_free; 826b053b439SMartin KaFai Lau 827f7f62c71SSandipan Das img += lens[i]; 828f7f62c71SSandipan Das 829f7f62c71SSandipan Das if (json_output) 830f7f62c71SSandipan Das jsonw_end_object(json_wtr); 831f7f62c71SSandipan Das else 832f7f62c71SSandipan Das printf("\n"); 833f7f62c71SSandipan Das } 834f7f62c71SSandipan Das 835f7f62c71SSandipan Das if (json_output) 836f7f62c71SSandipan Das jsonw_end_array(json_wtr); 837f7f62c71SSandipan Das } else { 83855b4de58SQuentin Monnet if (disasm_print_insn(buf, member_len, opcodes, name, 83955b4de58SQuentin Monnet disasm_opt, btf, NULL, 0, 0, 84055b4de58SQuentin Monnet false)) 84155b4de58SQuentin Monnet goto exit_free; 842f7f62c71SSandipan Das } 843b6c1cedbSJiong Wang } else if (visual) { 844b6c1cedbSJiong Wang if (json_output) 845b6c1cedbSJiong Wang jsonw_null(json_wtr); 846b6c1cedbSJiong Wang else 847cae73f23SSong Liu dump_xlated_cfg(buf, member_len); 8487105e828SDaniel Borkmann } else { 8497105e828SDaniel Borkmann kernel_syms_load(&dd); 850cae73f23SSong Liu dd.nr_jited_ksyms = info->nr_jited_ksyms; 85109f44b75SAndrii Nakryiko dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 852254471e5SYonghong Song dd.btf = btf; 853254471e5SYonghong Song dd.func_info = func_info; 854cae73f23SSong Liu dd.finfo_rec_size = info->func_info_rec_size; 855b053b439SMartin KaFai Lau dd.prog_linfo = prog_linfo; 856f84192eeSSandipan Das 857f05e2c32SQuentin Monnet if (json_output) 858cae73f23SSong Liu dump_xlated_json(&dd, buf, member_len, opcodes, 859b053b439SMartin KaFai Lau linum); 860f05e2c32SQuentin Monnet else 861cae73f23SSong Liu dump_xlated_plain(&dd, buf, member_len, opcodes, 862b053b439SMartin KaFai Lau linum); 8637105e828SDaniel Borkmann kernel_syms_destroy(&dd); 8647105e828SDaniel Borkmann } 86571bb428fSJakub Kicinski 866ebbd7f64SQuentin Monnet err = 0; 867369e955bSQuentin Monnet 868ebbd7f64SQuentin Monnet exit_free: 869ebbd7f64SQuentin Monnet btf__free(btf); 870ebbd7f64SQuentin Monnet bpf_prog_linfo__free(prog_linfo); 871ebbd7f64SQuentin Monnet return err; 872ec202509SPaul Chaignon } 87371bb428fSJakub Kicinski 874ec202509SPaul Chaignon static int do_dump(int argc, char **argv) 875ec202509SPaul Chaignon { 876c59765cfSDave Marchevsky struct bpf_prog_info info; 877c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 878c59765cfSDave Marchevsky size_t info_data_sz = 0; 879c59765cfSDave Marchevsky void *info_data = NULL; 880ec202509SPaul Chaignon char *filepath = NULL; 881ec202509SPaul Chaignon bool opcodes = false; 882ec202509SPaul Chaignon bool visual = false; 883ec202509SPaul Chaignon enum dump_mode mode; 884ec202509SPaul Chaignon bool linum = false; 885ec202509SPaul Chaignon int nb_fds, i = 0; 886c59765cfSDave Marchevsky int *fds = NULL; 887ec202509SPaul Chaignon int err = -1; 888ec202509SPaul Chaignon 889ec202509SPaul Chaignon if (is_prefix(*argv, "jited")) { 890ec202509SPaul Chaignon if (disasm_init()) 89171bb428fSJakub Kicinski return -1; 892ec202509SPaul Chaignon mode = DUMP_JITED; 893ec202509SPaul Chaignon } else if (is_prefix(*argv, "xlated")) { 894ec202509SPaul Chaignon mode = DUMP_XLATED; 895ec202509SPaul Chaignon } else { 896ec202509SPaul Chaignon p_err("expected 'xlated' or 'jited', got: %s", *argv); 897ec202509SPaul Chaignon return -1; 898ec202509SPaul Chaignon } 899ec202509SPaul Chaignon NEXT_ARG(); 900ec202509SPaul Chaignon 901ec202509SPaul Chaignon if (argc < 2) 902ec202509SPaul Chaignon usage(); 903ec202509SPaul Chaignon 904ec202509SPaul Chaignon fds = malloc(sizeof(int)); 905ec202509SPaul Chaignon if (!fds) { 906ec202509SPaul Chaignon p_err("mem alloc failed"); 907ec202509SPaul Chaignon return -1; 908ec202509SPaul Chaignon } 909ec202509SPaul Chaignon nb_fds = prog_parse_fds(&argc, &argv, &fds); 910ec202509SPaul Chaignon if (nb_fds < 1) 911ec202509SPaul Chaignon goto exit_free; 912ec202509SPaul Chaignon 913ec202509SPaul Chaignon if (is_prefix(*argv, "file")) { 914ec202509SPaul Chaignon NEXT_ARG(); 915ec202509SPaul Chaignon if (!argc) { 916ec202509SPaul Chaignon p_err("expected file path"); 917ec202509SPaul Chaignon goto exit_close; 918ec202509SPaul Chaignon } 919ec202509SPaul Chaignon if (nb_fds > 1) { 920ec202509SPaul Chaignon p_err("several programs matched"); 921ec202509SPaul Chaignon goto exit_close; 922ec202509SPaul Chaignon } 923ec202509SPaul Chaignon 924ec202509SPaul Chaignon filepath = *argv; 925ec202509SPaul Chaignon NEXT_ARG(); 926ec202509SPaul Chaignon } else if (is_prefix(*argv, "opcodes")) { 927ec202509SPaul Chaignon opcodes = true; 928ec202509SPaul Chaignon NEXT_ARG(); 929ec202509SPaul Chaignon } else if (is_prefix(*argv, "visual")) { 930ec202509SPaul Chaignon if (nb_fds > 1) { 931ec202509SPaul Chaignon p_err("several programs matched"); 932ec202509SPaul Chaignon goto exit_close; 933ec202509SPaul Chaignon } 934ec202509SPaul Chaignon 935ec202509SPaul Chaignon visual = true; 936ec202509SPaul Chaignon NEXT_ARG(); 937ec202509SPaul Chaignon } else if (is_prefix(*argv, "linum")) { 938ec202509SPaul Chaignon linum = true; 939ec202509SPaul Chaignon NEXT_ARG(); 940ec202509SPaul Chaignon } 941ec202509SPaul Chaignon 942ec202509SPaul Chaignon if (argc) { 943ec202509SPaul Chaignon usage(); 944ec202509SPaul Chaignon goto exit_close; 945ec202509SPaul Chaignon } 946ec202509SPaul Chaignon 947ec202509SPaul Chaignon if (json_output && nb_fds > 1) 948ec202509SPaul Chaignon jsonw_start_array(json_wtr); /* root array */ 949ec202509SPaul Chaignon for (i = 0; i < nb_fds; i++) { 950c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 951c59765cfSDave Marchevsky 952*38f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len); 953c59765cfSDave Marchevsky if (err) { 954c59765cfSDave Marchevsky p_err("can't get prog info: %s", strerror(errno)); 955c59765cfSDave Marchevsky break; 956c59765cfSDave Marchevsky } 957c59765cfSDave Marchevsky 958c59765cfSDave Marchevsky err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 959c59765cfSDave Marchevsky if (err) { 960c59765cfSDave Marchevsky p_err("can't grow prog info_data"); 961c59765cfSDave Marchevsky break; 962c59765cfSDave Marchevsky } 963c59765cfSDave Marchevsky 964*38f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len); 965c59765cfSDave Marchevsky if (err) { 966ec202509SPaul Chaignon p_err("can't get prog info: %s", strerror(errno)); 967ec202509SPaul Chaignon break; 968ec202509SPaul Chaignon } 969ec202509SPaul Chaignon 970ec202509SPaul Chaignon if (json_output && nb_fds > 1) { 971ec202509SPaul Chaignon jsonw_start_object(json_wtr); /* prog object */ 972b662000aSRaman Shukhau print_prog_header_json(&info, fds[i]); 973ec202509SPaul Chaignon jsonw_name(json_wtr, "insns"); 974ec202509SPaul Chaignon } else if (nb_fds > 1) { 975b662000aSRaman Shukhau print_prog_header_plain(&info, fds[i]); 976ec202509SPaul Chaignon } 977ec202509SPaul Chaignon 978c59765cfSDave Marchevsky err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 979ec202509SPaul Chaignon 980ec202509SPaul Chaignon if (json_output && nb_fds > 1) 981ec202509SPaul Chaignon jsonw_end_object(json_wtr); /* prog object */ 982ec202509SPaul Chaignon else if (i != nb_fds - 1 && nb_fds > 1) 983ec202509SPaul Chaignon printf("\n"); 984ec202509SPaul Chaignon 985ec202509SPaul Chaignon if (err) 986ec202509SPaul Chaignon break; 987ec202509SPaul Chaignon close(fds[i]); 988ec202509SPaul Chaignon } 989ec202509SPaul Chaignon if (json_output && nb_fds > 1) 990ec202509SPaul Chaignon jsonw_end_array(json_wtr); /* root array */ 991ec202509SPaul Chaignon 992ec202509SPaul Chaignon exit_close: 993ec202509SPaul Chaignon for (; i < nb_fds; i++) 994ec202509SPaul Chaignon close(fds[i]); 995ec202509SPaul Chaignon exit_free: 996c59765cfSDave Marchevsky free(info_data); 997ec202509SPaul Chaignon free(fds); 998ec202509SPaul Chaignon return err; 99971bb428fSJakub Kicinski } 100071bb428fSJakub Kicinski 100171bb428fSJakub Kicinski static int do_pin(int argc, char **argv) 100271bb428fSJakub Kicinski { 1003004b45c0SQuentin Monnet int err; 1004004b45c0SQuentin Monnet 100575a1e792SQuentin Monnet err = do_pin_any(argc, argv, prog_parse_fd); 1006004b45c0SQuentin Monnet if (!err && json_output) 1007004b45c0SQuentin Monnet jsonw_null(json_wtr); 1008004b45c0SQuentin Monnet return err; 100971bb428fSJakub Kicinski } 101071bb428fSJakub Kicinski 10113ff5a4dcSJakub Kicinski struct map_replace { 10123ff5a4dcSJakub Kicinski int idx; 10133ff5a4dcSJakub Kicinski int fd; 10143ff5a4dcSJakub Kicinski char *name; 10153ff5a4dcSJakub Kicinski }; 10163ff5a4dcSJakub Kicinski 1017c101189bSQuentin Monnet static int map_replace_compar(const void *p1, const void *p2) 10183ff5a4dcSJakub Kicinski { 10193ff5a4dcSJakub Kicinski const struct map_replace *a = p1, *b = p2; 10203ff5a4dcSJakub Kicinski 10213ff5a4dcSJakub Kicinski return a->idx - b->idx; 10223ff5a4dcSJakub Kicinski } 10233ff5a4dcSJakub Kicinski 1024092f0892SStanislav Fomichev static int parse_attach_detach_args(int argc, char **argv, int *progfd, 1025092f0892SStanislav Fomichev enum bpf_attach_type *attach_type, 1026092f0892SStanislav Fomichev int *mapfd) 1027092f0892SStanislav Fomichev { 1028092f0892SStanislav Fomichev if (!REQ_ARGS(3)) 1029092f0892SStanislav Fomichev return -EINVAL; 1030092f0892SStanislav Fomichev 1031092f0892SStanislav Fomichev *progfd = prog_parse_fd(&argc, &argv); 1032092f0892SStanislav Fomichev if (*progfd < 0) 1033092f0892SStanislav Fomichev return *progfd; 1034092f0892SStanislav Fomichev 1035092f0892SStanislav Fomichev *attach_type = parse_attach_type(*argv); 1036092f0892SStanislav Fomichev if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 1037092f0892SStanislav Fomichev p_err("invalid attach/detach type"); 1038092f0892SStanislav Fomichev return -EINVAL; 1039092f0892SStanislav Fomichev } 1040092f0892SStanislav Fomichev 1041092f0892SStanislav Fomichev if (*attach_type == BPF_FLOW_DISSECTOR) { 1042f9b7ff0dSLorenz Bauer *mapfd = 0; 1043092f0892SStanislav Fomichev return 0; 1044092f0892SStanislav Fomichev } 1045092f0892SStanislav Fomichev 1046092f0892SStanislav Fomichev NEXT_ARG(); 1047092f0892SStanislav Fomichev if (!REQ_ARGS(2)) 1048092f0892SStanislav Fomichev return -EINVAL; 1049092f0892SStanislav Fomichev 1050092f0892SStanislav Fomichev *mapfd = map_parse_fd(&argc, &argv); 1051092f0892SStanislav Fomichev if (*mapfd < 0) 1052092f0892SStanislav Fomichev return *mapfd; 1053092f0892SStanislav Fomichev 1054092f0892SStanislav Fomichev return 0; 1055092f0892SStanislav Fomichev } 1056092f0892SStanislav Fomichev 1057b7d3826cSJohn Fastabend static int do_attach(int argc, char **argv) 1058b7d3826cSJohn Fastabend { 1059b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1060092f0892SStanislav Fomichev int err, progfd; 1061092f0892SStanislav Fomichev int mapfd; 1062b7d3826cSJohn Fastabend 1063092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1064092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1065092f0892SStanislav Fomichev if (err) 1066092f0892SStanislav Fomichev return err; 1067b7d3826cSJohn Fastabend 1068b7d3826cSJohn Fastabend err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 1069b7d3826cSJohn Fastabend if (err) { 1070b7d3826cSJohn Fastabend p_err("failed prog attach to map"); 1071b7d3826cSJohn Fastabend return -EINVAL; 1072b7d3826cSJohn Fastabend } 1073b7d3826cSJohn Fastabend 1074b7d3826cSJohn Fastabend if (json_output) 1075b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1076b7d3826cSJohn Fastabend return 0; 1077b7d3826cSJohn Fastabend } 1078b7d3826cSJohn Fastabend 1079b7d3826cSJohn Fastabend static int do_detach(int argc, char **argv) 1080b7d3826cSJohn Fastabend { 1081b7d3826cSJohn Fastabend enum bpf_attach_type attach_type; 1082092f0892SStanislav Fomichev int err, progfd; 1083092f0892SStanislav Fomichev int mapfd; 1084b7d3826cSJohn Fastabend 1085092f0892SStanislav Fomichev err = parse_attach_detach_args(argc, argv, 1086092f0892SStanislav Fomichev &progfd, &attach_type, &mapfd); 1087092f0892SStanislav Fomichev if (err) 1088092f0892SStanislav Fomichev return err; 1089b7d3826cSJohn Fastabend 1090b7d3826cSJohn Fastabend err = bpf_prog_detach2(progfd, mapfd, attach_type); 1091b7d3826cSJohn Fastabend if (err) { 1092b7d3826cSJohn Fastabend p_err("failed prog detach from map"); 1093b7d3826cSJohn Fastabend return -EINVAL; 1094b7d3826cSJohn Fastabend } 1095b7d3826cSJohn Fastabend 1096b7d3826cSJohn Fastabend if (json_output) 1097b7d3826cSJohn Fastabend jsonw_null(json_wtr); 1098b7d3826cSJohn Fastabend return 0; 1099b7d3826cSJohn Fastabend } 110077380998SStanislav Fomichev 1101ba95c745SQuentin Monnet static int check_single_stdin(char *file_data_in, char *file_ctx_in) 1102ba95c745SQuentin Monnet { 1103ba95c745SQuentin Monnet if (file_data_in && file_ctx_in && 1104ba95c745SQuentin Monnet !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 1105ba95c745SQuentin Monnet p_err("cannot use standard input for both data_in and ctx_in"); 1106ba95c745SQuentin Monnet return -1; 1107ba95c745SQuentin Monnet } 1108ba95c745SQuentin Monnet 1109ba95c745SQuentin Monnet return 0; 1110ba95c745SQuentin Monnet } 1111ba95c745SQuentin Monnet 1112ba95c745SQuentin Monnet static int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 1113ba95c745SQuentin Monnet { 1114ba95c745SQuentin Monnet size_t block_size = 256; 1115ba95c745SQuentin Monnet size_t buf_size = block_size; 1116ba95c745SQuentin Monnet size_t nb_read = 0; 1117ba95c745SQuentin Monnet void *tmp; 1118ba95c745SQuentin Monnet FILE *f; 1119ba95c745SQuentin Monnet 1120ba95c745SQuentin Monnet if (!fname) { 1121ba95c745SQuentin Monnet *data_ptr = NULL; 1122ba95c745SQuentin Monnet *size = 0; 1123ba95c745SQuentin Monnet return 0; 1124ba95c745SQuentin Monnet } 1125ba95c745SQuentin Monnet 1126ba95c745SQuentin Monnet if (!strcmp(fname, "-")) 1127ba95c745SQuentin Monnet f = stdin; 1128ba95c745SQuentin Monnet else 1129ba95c745SQuentin Monnet f = fopen(fname, "r"); 1130ba95c745SQuentin Monnet if (!f) { 1131ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1132ba95c745SQuentin Monnet return -1; 1133ba95c745SQuentin Monnet } 1134ba95c745SQuentin Monnet 1135ba95c745SQuentin Monnet *data_ptr = malloc(block_size); 1136ba95c745SQuentin Monnet if (!*data_ptr) { 1137ba95c745SQuentin Monnet p_err("failed to allocate memory for data_in/ctx_in: %s", 1138ba95c745SQuentin Monnet strerror(errno)); 1139ba95c745SQuentin Monnet goto err_fclose; 1140ba95c745SQuentin Monnet } 1141ba95c745SQuentin Monnet 1142ba95c745SQuentin Monnet while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 1143ba95c745SQuentin Monnet if (feof(f)) 1144ba95c745SQuentin Monnet break; 1145ba95c745SQuentin Monnet if (ferror(f)) { 1146ba95c745SQuentin Monnet p_err("failed to read data_in/ctx_in from %s: %s", 1147ba95c745SQuentin Monnet fname, strerror(errno)); 1148ba95c745SQuentin Monnet goto err_free; 1149ba95c745SQuentin Monnet } 1150ba95c745SQuentin Monnet if (nb_read > buf_size - block_size) { 1151ba95c745SQuentin Monnet if (buf_size == UINT32_MAX) { 1152ba95c745SQuentin Monnet p_err("data_in/ctx_in is too long (max: %d)", 1153ba95c745SQuentin Monnet UINT32_MAX); 1154ba95c745SQuentin Monnet goto err_free; 1155ba95c745SQuentin Monnet } 1156ba95c745SQuentin Monnet /* No space for fread()-ing next chunk; realloc() */ 1157ba95c745SQuentin Monnet buf_size *= 2; 1158ba95c745SQuentin Monnet tmp = realloc(*data_ptr, buf_size); 1159ba95c745SQuentin Monnet if (!tmp) { 1160ba95c745SQuentin Monnet p_err("failed to reallocate data_in/ctx_in: %s", 1161ba95c745SQuentin Monnet strerror(errno)); 1162ba95c745SQuentin Monnet goto err_free; 1163ba95c745SQuentin Monnet } 1164ba95c745SQuentin Monnet *data_ptr = tmp; 1165ba95c745SQuentin Monnet } 1166ba95c745SQuentin Monnet } 1167ba95c745SQuentin Monnet if (f != stdin) 1168ba95c745SQuentin Monnet fclose(f); 1169ba95c745SQuentin Monnet 1170ba95c745SQuentin Monnet *size = nb_read; 1171ba95c745SQuentin Monnet return 0; 1172ba95c745SQuentin Monnet 1173ba95c745SQuentin Monnet err_free: 1174ba95c745SQuentin Monnet free(*data_ptr); 1175ba95c745SQuentin Monnet *data_ptr = NULL; 1176ba95c745SQuentin Monnet err_fclose: 1177ba95c745SQuentin Monnet if (f != stdin) 1178ba95c745SQuentin Monnet fclose(f); 1179ba95c745SQuentin Monnet return -1; 1180ba95c745SQuentin Monnet } 1181ba95c745SQuentin Monnet 1182ba95c745SQuentin Monnet static void hex_print(void *data, unsigned int size, FILE *f) 1183ba95c745SQuentin Monnet { 1184ba95c745SQuentin Monnet size_t i, j; 1185ba95c745SQuentin Monnet char c; 1186ba95c745SQuentin Monnet 1187ba95c745SQuentin Monnet for (i = 0; i < size; i += 16) { 1188ba95c745SQuentin Monnet /* Row offset */ 1189ba95c745SQuentin Monnet fprintf(f, "%07zx\t", i); 1190ba95c745SQuentin Monnet 1191ba95c745SQuentin Monnet /* Hexadecimal values */ 1192ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) 1193ba95c745SQuentin Monnet fprintf(f, "%02x%s", *(uint8_t *)(data + j), 1194ba95c745SQuentin Monnet j % 2 ? " " : ""); 1195ba95c745SQuentin Monnet for (; j < i + 16; j++) 1196ba95c745SQuentin Monnet fprintf(f, " %s", j % 2 ? " " : ""); 1197ba95c745SQuentin Monnet 1198ba95c745SQuentin Monnet /* ASCII values (if relevant), '.' otherwise */ 1199ba95c745SQuentin Monnet fprintf(f, "| "); 1200ba95c745SQuentin Monnet for (j = i; j < i + 16 && j < size; j++) { 1201ba95c745SQuentin Monnet c = *(char *)(data + j); 1202ba95c745SQuentin Monnet if (c < ' ' || c > '~') 1203ba95c745SQuentin Monnet c = '.'; 1204ba95c745SQuentin Monnet fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 1205ba95c745SQuentin Monnet } 1206ba95c745SQuentin Monnet 1207ba95c745SQuentin Monnet fprintf(f, "\n"); 1208ba95c745SQuentin Monnet } 1209ba95c745SQuentin Monnet } 1210ba95c745SQuentin Monnet 1211ba95c745SQuentin Monnet static int 1212ba95c745SQuentin Monnet print_run_output(void *data, unsigned int size, const char *fname, 1213ba95c745SQuentin Monnet const char *json_key) 1214ba95c745SQuentin Monnet { 1215ba95c745SQuentin Monnet size_t nb_written; 1216ba95c745SQuentin Monnet FILE *f; 1217ba95c745SQuentin Monnet 1218ba95c745SQuentin Monnet if (!fname) 1219ba95c745SQuentin Monnet return 0; 1220ba95c745SQuentin Monnet 1221ba95c745SQuentin Monnet if (!strcmp(fname, "-")) { 1222ba95c745SQuentin Monnet f = stdout; 1223ba95c745SQuentin Monnet if (json_output) { 1224ba95c745SQuentin Monnet jsonw_name(json_wtr, json_key); 1225ba95c745SQuentin Monnet print_data_json(data, size); 1226ba95c745SQuentin Monnet } else { 1227ba95c745SQuentin Monnet hex_print(data, size, f); 1228ba95c745SQuentin Monnet } 1229ba95c745SQuentin Monnet return 0; 1230ba95c745SQuentin Monnet } 1231ba95c745SQuentin Monnet 1232ba95c745SQuentin Monnet f = fopen(fname, "w"); 1233ba95c745SQuentin Monnet if (!f) { 1234ba95c745SQuentin Monnet p_err("failed to open %s: %s", fname, strerror(errno)); 1235ba95c745SQuentin Monnet return -1; 1236ba95c745SQuentin Monnet } 1237ba95c745SQuentin Monnet 1238ba95c745SQuentin Monnet nb_written = fwrite(data, 1, size, f); 1239ba95c745SQuentin Monnet fclose(f); 1240ba95c745SQuentin Monnet if (nb_written != size) { 1241ba95c745SQuentin Monnet p_err("failed to write output data/ctx: %s", strerror(errno)); 1242ba95c745SQuentin Monnet return -1; 1243ba95c745SQuentin Monnet } 1244ba95c745SQuentin Monnet 1245ba95c745SQuentin Monnet return 0; 1246ba95c745SQuentin Monnet } 1247ba95c745SQuentin Monnet 1248ba95c745SQuentin Monnet static int alloc_run_data(void **data_ptr, unsigned int size_out) 1249ba95c745SQuentin Monnet { 1250ba95c745SQuentin Monnet *data_ptr = calloc(size_out, 1); 1251ba95c745SQuentin Monnet if (!*data_ptr) { 1252ba95c745SQuentin Monnet p_err("failed to allocate memory for output data/ctx: %s", 1253ba95c745SQuentin Monnet strerror(errno)); 1254ba95c745SQuentin Monnet return -1; 1255ba95c745SQuentin Monnet } 1256ba95c745SQuentin Monnet 1257ba95c745SQuentin Monnet return 0; 1258ba95c745SQuentin Monnet } 1259ba95c745SQuentin Monnet 1260ba95c745SQuentin Monnet static int do_run(int argc, char **argv) 1261ba95c745SQuentin Monnet { 1262ba95c745SQuentin Monnet char *data_fname_in = NULL, *data_fname_out = NULL; 1263ba95c745SQuentin Monnet char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 1264ba95c745SQuentin Monnet const unsigned int default_size = SZ_32K; 1265ba95c745SQuentin Monnet void *data_in = NULL, *data_out = NULL; 1266ba95c745SQuentin Monnet void *ctx_in = NULL, *ctx_out = NULL; 1267ba95c745SQuentin Monnet unsigned int repeat = 1; 1268ba95c745SQuentin Monnet int fd, err; 12699cce5313SDelyan Kratunov LIBBPF_OPTS(bpf_test_run_opts, test_attr); 1270ba95c745SQuentin Monnet 1271ba95c745SQuentin Monnet if (!REQ_ARGS(4)) 1272ba95c745SQuentin Monnet return -1; 1273ba95c745SQuentin Monnet 1274ba95c745SQuentin Monnet fd = prog_parse_fd(&argc, &argv); 1275ba95c745SQuentin Monnet if (fd < 0) 1276ba95c745SQuentin Monnet return -1; 1277ba95c745SQuentin Monnet 1278ba95c745SQuentin Monnet while (argc) { 1279ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "data_in", "data_out", 1280ba95c745SQuentin Monnet "data_size_out", NULL)) 1281ba95c745SQuentin Monnet return -1; 1282ba95c745SQuentin Monnet if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 1283ba95c745SQuentin Monnet "ctx_size_out", NULL)) 1284ba95c745SQuentin Monnet return -1; 1285ba95c745SQuentin Monnet 1286ba95c745SQuentin Monnet if (is_prefix(*argv, "data_in")) { 1287ba95c745SQuentin Monnet NEXT_ARG(); 1288ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1289ba95c745SQuentin Monnet return -1; 1290ba95c745SQuentin Monnet 1291ba95c745SQuentin Monnet data_fname_in = GET_ARG(); 1292ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1293ba95c745SQuentin Monnet return -1; 1294ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_out")) { 1295ba95c745SQuentin Monnet NEXT_ARG(); 1296ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1297ba95c745SQuentin Monnet return -1; 1298ba95c745SQuentin Monnet 1299ba95c745SQuentin Monnet data_fname_out = GET_ARG(); 1300ba95c745SQuentin Monnet } else if (is_prefix(*argv, "data_size_out")) { 1301ba95c745SQuentin Monnet char *endptr; 1302ba95c745SQuentin Monnet 1303ba95c745SQuentin Monnet NEXT_ARG(); 1304ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1305ba95c745SQuentin Monnet return -1; 1306ba95c745SQuentin Monnet 1307ba95c745SQuentin Monnet test_attr.data_size_out = strtoul(*argv, &endptr, 0); 1308ba95c745SQuentin Monnet if (*endptr) { 1309ba95c745SQuentin Monnet p_err("can't parse %s as output data size", 1310ba95c745SQuentin Monnet *argv); 1311ba95c745SQuentin Monnet return -1; 1312ba95c745SQuentin Monnet } 1313ba95c745SQuentin Monnet NEXT_ARG(); 1314ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_in")) { 1315ba95c745SQuentin Monnet NEXT_ARG(); 1316ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1317ba95c745SQuentin Monnet return -1; 1318ba95c745SQuentin Monnet 1319ba95c745SQuentin Monnet ctx_fname_in = GET_ARG(); 1320ba95c745SQuentin Monnet if (check_single_stdin(data_fname_in, ctx_fname_in)) 1321ba95c745SQuentin Monnet return -1; 1322ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_out")) { 1323ba95c745SQuentin Monnet NEXT_ARG(); 1324ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1325ba95c745SQuentin Monnet return -1; 1326ba95c745SQuentin Monnet 1327ba95c745SQuentin Monnet ctx_fname_out = GET_ARG(); 1328ba95c745SQuentin Monnet } else if (is_prefix(*argv, "ctx_size_out")) { 1329ba95c745SQuentin Monnet char *endptr; 1330ba95c745SQuentin Monnet 1331ba95c745SQuentin Monnet NEXT_ARG(); 1332ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1333ba95c745SQuentin Monnet return -1; 1334ba95c745SQuentin Monnet 1335ba95c745SQuentin Monnet test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 1336ba95c745SQuentin Monnet if (*endptr) { 1337ba95c745SQuentin Monnet p_err("can't parse %s as output context size", 1338ba95c745SQuentin Monnet *argv); 1339ba95c745SQuentin Monnet return -1; 1340ba95c745SQuentin Monnet } 1341ba95c745SQuentin Monnet NEXT_ARG(); 1342ba95c745SQuentin Monnet } else if (is_prefix(*argv, "repeat")) { 1343ba95c745SQuentin Monnet char *endptr; 1344ba95c745SQuentin Monnet 1345ba95c745SQuentin Monnet NEXT_ARG(); 1346ba95c745SQuentin Monnet if (!REQ_ARGS(1)) 1347ba95c745SQuentin Monnet return -1; 1348ba95c745SQuentin Monnet 1349ba95c745SQuentin Monnet repeat = strtoul(*argv, &endptr, 0); 1350ba95c745SQuentin Monnet if (*endptr) { 1351ba95c745SQuentin Monnet p_err("can't parse %s as repeat number", 1352ba95c745SQuentin Monnet *argv); 1353ba95c745SQuentin Monnet return -1; 1354ba95c745SQuentin Monnet } 1355ba95c745SQuentin Monnet NEXT_ARG(); 1356ba95c745SQuentin Monnet } else { 1357ba95c745SQuentin Monnet p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 1358ba95c745SQuentin Monnet *argv); 1359ba95c745SQuentin Monnet return -1; 1360ba95c745SQuentin Monnet } 1361ba95c745SQuentin Monnet } 1362ba95c745SQuentin Monnet 1363ba95c745SQuentin Monnet err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 1364ba95c745SQuentin Monnet if (err) 1365ba95c745SQuentin Monnet return -1; 1366ba95c745SQuentin Monnet 1367ba95c745SQuentin Monnet if (data_in) { 1368ba95c745SQuentin Monnet if (!test_attr.data_size_out) 1369ba95c745SQuentin Monnet test_attr.data_size_out = default_size; 1370ba95c745SQuentin Monnet err = alloc_run_data(&data_out, test_attr.data_size_out); 1371ba95c745SQuentin Monnet if (err) 1372ba95c745SQuentin Monnet goto free_data_in; 1373ba95c745SQuentin Monnet } 1374ba95c745SQuentin Monnet 1375ba95c745SQuentin Monnet err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 1376ba95c745SQuentin Monnet if (err) 1377ba95c745SQuentin Monnet goto free_data_out; 1378ba95c745SQuentin Monnet 1379ba95c745SQuentin Monnet if (ctx_in) { 1380ba95c745SQuentin Monnet if (!test_attr.ctx_size_out) 1381ba95c745SQuentin Monnet test_attr.ctx_size_out = default_size; 1382ba95c745SQuentin Monnet err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 1383ba95c745SQuentin Monnet if (err) 1384ba95c745SQuentin Monnet goto free_ctx_in; 1385ba95c745SQuentin Monnet } 1386ba95c745SQuentin Monnet 1387ba95c745SQuentin Monnet test_attr.repeat = repeat; 1388ba95c745SQuentin Monnet test_attr.data_in = data_in; 1389ba95c745SQuentin Monnet test_attr.data_out = data_out; 1390ba95c745SQuentin Monnet test_attr.ctx_in = ctx_in; 1391ba95c745SQuentin Monnet test_attr.ctx_out = ctx_out; 1392ba95c745SQuentin Monnet 13939cce5313SDelyan Kratunov err = bpf_prog_test_run_opts(fd, &test_attr); 1394ba95c745SQuentin Monnet if (err) { 1395ba95c745SQuentin Monnet p_err("failed to run program: %s", strerror(errno)); 1396ba95c745SQuentin Monnet goto free_ctx_out; 1397ba95c745SQuentin Monnet } 1398ba95c745SQuentin Monnet 1399ba95c745SQuentin Monnet err = 0; 1400ba95c745SQuentin Monnet 1401ba95c745SQuentin Monnet if (json_output) 1402ba95c745SQuentin Monnet jsonw_start_object(json_wtr); /* root */ 1403ba95c745SQuentin Monnet 1404ba95c745SQuentin Monnet /* Do not exit on errors occurring when printing output data/context, 1405ba95c745SQuentin Monnet * we still want to print return value and duration for program run. 1406ba95c745SQuentin Monnet */ 1407ba95c745SQuentin Monnet if (test_attr.data_size_out) 1408ba95c745SQuentin Monnet err += print_run_output(test_attr.data_out, 1409ba95c745SQuentin Monnet test_attr.data_size_out, 1410ba95c745SQuentin Monnet data_fname_out, "data_out"); 1411ba95c745SQuentin Monnet if (test_attr.ctx_size_out) 1412ba95c745SQuentin Monnet err += print_run_output(test_attr.ctx_out, 1413ba95c745SQuentin Monnet test_attr.ctx_size_out, 1414ba95c745SQuentin Monnet ctx_fname_out, "ctx_out"); 1415ba95c745SQuentin Monnet 1416ba95c745SQuentin Monnet if (json_output) { 1417ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "retval", test_attr.retval); 1418ba95c745SQuentin Monnet jsonw_uint_field(json_wtr, "duration", test_attr.duration); 1419ba95c745SQuentin Monnet jsonw_end_object(json_wtr); /* root */ 1420ba95c745SQuentin Monnet } else { 1421ba95c745SQuentin Monnet fprintf(stdout, "Return value: %u, duration%s: %uns\n", 1422ba95c745SQuentin Monnet test_attr.retval, 1423ba95c745SQuentin Monnet repeat > 1 ? " (average)" : "", test_attr.duration); 1424ba95c745SQuentin Monnet } 1425ba95c745SQuentin Monnet 1426ba95c745SQuentin Monnet free_ctx_out: 1427ba95c745SQuentin Monnet free(ctx_out); 1428ba95c745SQuentin Monnet free_ctx_in: 1429ba95c745SQuentin Monnet free(ctx_in); 1430ba95c745SQuentin Monnet free_data_out: 1431ba95c745SQuentin Monnet free(data_out); 1432ba95c745SQuentin Monnet free_data_in: 1433ba95c745SQuentin Monnet free(data_in); 1434ba95c745SQuentin Monnet 1435ba95c745SQuentin Monnet return err; 1436ba95c745SQuentin Monnet } 1437ba95c745SQuentin Monnet 14386ae32b29SQuentin Monnet static int 14396ae32b29SQuentin Monnet get_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 14406ae32b29SQuentin Monnet enum bpf_attach_type *expected_attach_type) 14416ae32b29SQuentin Monnet { 14426ae32b29SQuentin Monnet libbpf_print_fn_t print_backup; 14436ae32b29SQuentin Monnet int ret; 14446ae32b29SQuentin Monnet 14456ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14466ae32b29SQuentin Monnet if (!ret) 14476ae32b29SQuentin Monnet return ret; 14486ae32b29SQuentin Monnet 14496ae32b29SQuentin Monnet /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 14506ae32b29SQuentin Monnet print_backup = libbpf_set_print(print_all_levels); 14516ae32b29SQuentin Monnet ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 14526ae32b29SQuentin Monnet libbpf_set_print(print_backup); 14536ae32b29SQuentin Monnet 14546ae32b29SQuentin Monnet return ret; 14556ae32b29SQuentin Monnet } 14566ae32b29SQuentin Monnet 145719526e70SWang Yufen static int 145819526e70SWang Yufen auto_attach_program(struct bpf_program *prog, const char *path) 145919526e70SWang Yufen { 146019526e70SWang Yufen struct bpf_link *link; 146119526e70SWang Yufen int err; 146219526e70SWang Yufen 146319526e70SWang Yufen link = bpf_program__attach(prog); 146419526e70SWang Yufen if (!link) { 146519526e70SWang Yufen p_info("Program %s does not support autoattach, falling back to pinning", 146619526e70SWang Yufen bpf_program__name(prog)); 146719526e70SWang Yufen return bpf_obj_pin(bpf_program__fd(prog), path); 146819526e70SWang Yufen } 146919526e70SWang Yufen 147019526e70SWang Yufen err = bpf_link__pin(link, path); 147119526e70SWang Yufen bpf_link__destroy(link); 147219526e70SWang Yufen return err; 147319526e70SWang Yufen } 147419526e70SWang Yufen 147519526e70SWang Yufen static int pathname_concat(char *buf, size_t buf_sz, const char *path, const char *name) 147619526e70SWang Yufen { 147719526e70SWang Yufen int len; 147819526e70SWang Yufen 147919526e70SWang Yufen len = snprintf(buf, buf_sz, "%s/%s", path, name); 148019526e70SWang Yufen if (len < 0) 148119526e70SWang Yufen return -EINVAL; 148219526e70SWang Yufen if ((size_t)len >= buf_sz) 148319526e70SWang Yufen return -ENAMETOOLONG; 148419526e70SWang Yufen 148519526e70SWang Yufen return 0; 148619526e70SWang Yufen } 148719526e70SWang Yufen 148819526e70SWang Yufen static int 148919526e70SWang Yufen auto_attach_programs(struct bpf_object *obj, const char *path) 149019526e70SWang Yufen { 149119526e70SWang Yufen struct bpf_program *prog; 149219526e70SWang Yufen char buf[PATH_MAX]; 149319526e70SWang Yufen int err; 149419526e70SWang Yufen 149519526e70SWang Yufen bpf_object__for_each_program(prog, obj) { 149619526e70SWang Yufen err = pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog)); 149719526e70SWang Yufen if (err) 149819526e70SWang Yufen goto err_unpin_programs; 149919526e70SWang Yufen 150019526e70SWang Yufen err = auto_attach_program(prog, buf); 150119526e70SWang Yufen if (err) 150219526e70SWang Yufen goto err_unpin_programs; 150319526e70SWang Yufen } 150419526e70SWang Yufen 150519526e70SWang Yufen return 0; 150619526e70SWang Yufen 150719526e70SWang Yufen err_unpin_programs: 150819526e70SWang Yufen while ((prog = bpf_object__prev_program(obj, prog))) { 150919526e70SWang Yufen if (pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog))) 151019526e70SWang Yufen continue; 151119526e70SWang Yufen 151219526e70SWang Yufen bpf_program__unpin(prog, buf); 151319526e70SWang Yufen } 151419526e70SWang Yufen 151519526e70SWang Yufen return err; 151619526e70SWang Yufen } 151719526e70SWang Yufen 151877380998SStanislav Fomichev static int load_with_options(int argc, char **argv, bool first_prog_only) 151949a086c2SRoman Gushchin { 152032e3e58eSAndrii Nakryiko enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 1521e00aca65SAndrii Nakryiko DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 1522e00aca65SAndrii Nakryiko .relaxed_maps = relaxed_maps, 1523e00aca65SAndrii Nakryiko ); 152455d77807SQuentin Monnet enum bpf_attach_type expected_attach_type; 15253ff5a4dcSJakub Kicinski struct map_replace *map_replace = NULL; 152677380998SStanislav Fomichev struct bpf_program *prog = NULL, *pos; 15273ff5a4dcSJakub Kicinski unsigned int old_map_fds = 0; 15283767a94bSStanislav Fomichev const char *pinmaps = NULL; 152919526e70SWang Yufen bool auto_attach = false; 153049a086c2SRoman Gushchin struct bpf_object *obj; 1531c8406848SJakub Kicinski struct bpf_map *map; 1532c8406848SJakub Kicinski const char *pinfile; 15333ff5a4dcSJakub Kicinski unsigned int i, j; 1534c8406848SJakub Kicinski __u32 ifindex = 0; 153532e3e58eSAndrii Nakryiko const char *file; 15363ff5a4dcSJakub Kicinski int idx, err; 153749a086c2SRoman Gushchin 153832e3e58eSAndrii Nakryiko 15398d1fc3deSJakub Kicinski if (!REQ_ARGS(2)) 15408d1fc3deSJakub Kicinski return -1; 154132e3e58eSAndrii Nakryiko file = GET_ARG(); 15428d1fc3deSJakub Kicinski pinfile = GET_ARG(); 154349a086c2SRoman Gushchin 1544ba6dd679SJakub Kicinski while (argc) { 154549f2cba3SJakub Kicinski if (is_prefix(*argv, "type")) { 154649f2cba3SJakub Kicinski NEXT_ARG(); 154749f2cba3SJakub Kicinski 154832e3e58eSAndrii Nakryiko if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 154949f2cba3SJakub Kicinski p_err("program type already specified"); 15503ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 155149f2cba3SJakub Kicinski } 155249f2cba3SJakub Kicinski if (!REQ_ARGS(1)) 15533ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 155449f2cba3SJakub Kicinski 1555314f14abSStanislav Fomichev err = libbpf_prog_type_by_name(*argv, &common_prog_type, 1556314f14abSStanislav Fomichev &expected_attach_type); 1557314f14abSStanislav Fomichev if (err < 0) { 155849f2cba3SJakub Kicinski /* Put a '/' at the end of type to appease libbpf */ 1559314f14abSStanislav Fomichev char *type = malloc(strlen(*argv) + 2); 1560314f14abSStanislav Fomichev 156149f2cba3SJakub Kicinski if (!type) { 156249f2cba3SJakub Kicinski p_err("mem alloc failed"); 15633ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 156449f2cba3SJakub Kicinski } 156549f2cba3SJakub Kicinski *type = 0; 156649f2cba3SJakub Kicinski strcat(type, *argv); 156749f2cba3SJakub Kicinski strcat(type, "/"); 156849f2cba3SJakub Kicinski 15696ae32b29SQuentin Monnet err = get_prog_type_by_name(type, &common_prog_type, 1570c8406848SJakub Kicinski &expected_attach_type); 157149f2cba3SJakub Kicinski free(type); 1572c76e4c22STaeung Song if (err < 0) 15733ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1574314f14abSStanislav Fomichev } 1575c76e4c22STaeung Song 157649f2cba3SJakub Kicinski NEXT_ARG(); 15773ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "map")) { 1578dde7011aSJakub Kicinski void *new_map_replace; 15793ff5a4dcSJakub Kicinski char *endptr, *name; 15803ff5a4dcSJakub Kicinski int fd; 15813ff5a4dcSJakub Kicinski 15823ff5a4dcSJakub Kicinski NEXT_ARG(); 15833ff5a4dcSJakub Kicinski 15843ff5a4dcSJakub Kicinski if (!REQ_ARGS(4)) 15853ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15863ff5a4dcSJakub Kicinski 15873ff5a4dcSJakub Kicinski if (is_prefix(*argv, "idx")) { 15883ff5a4dcSJakub Kicinski NEXT_ARG(); 15893ff5a4dcSJakub Kicinski 15903ff5a4dcSJakub Kicinski idx = strtoul(*argv, &endptr, 0); 15913ff5a4dcSJakub Kicinski if (*endptr) { 15923ff5a4dcSJakub Kicinski p_err("can't parse %s as IDX", *argv); 15933ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 15943ff5a4dcSJakub Kicinski } 15953ff5a4dcSJakub Kicinski name = NULL; 15963ff5a4dcSJakub Kicinski } else if (is_prefix(*argv, "name")) { 15973ff5a4dcSJakub Kicinski NEXT_ARG(); 15983ff5a4dcSJakub Kicinski 15993ff5a4dcSJakub Kicinski name = *argv; 16003ff5a4dcSJakub Kicinski idx = -1; 16013ff5a4dcSJakub Kicinski } else { 16023ff5a4dcSJakub Kicinski p_err("expected 'idx' or 'name', got: '%s'?", 16033ff5a4dcSJakub Kicinski *argv); 16043ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16053ff5a4dcSJakub Kicinski } 16063ff5a4dcSJakub Kicinski NEXT_ARG(); 16073ff5a4dcSJakub Kicinski 16083ff5a4dcSJakub Kicinski fd = map_parse_fd(&argc, &argv); 16093ff5a4dcSJakub Kicinski if (fd < 0) 16103ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16113ff5a4dcSJakub Kicinski 1612a19df713SMauricio Vásquez new_map_replace = libbpf_reallocarray(map_replace, 1613dde7011aSJakub Kicinski old_map_fds + 1, 16143ff5a4dcSJakub Kicinski sizeof(*map_replace)); 1615dde7011aSJakub Kicinski if (!new_map_replace) { 16163ff5a4dcSJakub Kicinski p_err("mem alloc failed"); 16173ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 16183ff5a4dcSJakub Kicinski } 1619dde7011aSJakub Kicinski map_replace = new_map_replace; 1620dde7011aSJakub Kicinski 16213ff5a4dcSJakub Kicinski map_replace[old_map_fds].idx = idx; 16223ff5a4dcSJakub Kicinski map_replace[old_map_fds].name = name; 16233ff5a4dcSJakub Kicinski map_replace[old_map_fds].fd = fd; 16243ff5a4dcSJakub Kicinski old_map_fds++; 162549f2cba3SJakub Kicinski } else if (is_prefix(*argv, "dev")) { 1626ba6dd679SJakub Kicinski NEXT_ARG(); 1627ba6dd679SJakub Kicinski 1628c8406848SJakub Kicinski if (ifindex) { 1629ba6dd679SJakub Kicinski p_err("offload device already specified"); 16303ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1631ba6dd679SJakub Kicinski } 1632ba6dd679SJakub Kicinski if (!REQ_ARGS(1)) 16333ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1634ba6dd679SJakub Kicinski 1635c8406848SJakub Kicinski ifindex = if_nametoindex(*argv); 1636c8406848SJakub Kicinski if (!ifindex) { 1637ba6dd679SJakub Kicinski p_err("unrecognized netdevice '%s': %s", 1638ba6dd679SJakub Kicinski *argv, strerror(errno)); 16393ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1640ba6dd679SJakub Kicinski } 1641ba6dd679SJakub Kicinski NEXT_ARG(); 16423767a94bSStanislav Fomichev } else if (is_prefix(*argv, "pinmaps")) { 16433767a94bSStanislav Fomichev NEXT_ARG(); 16443767a94bSStanislav Fomichev 16453767a94bSStanislav Fomichev if (!REQ_ARGS(1)) 16463767a94bSStanislav Fomichev goto err_free_reuse_maps; 16473767a94bSStanislav Fomichev 16483767a94bSStanislav Fomichev pinmaps = GET_ARG(); 164919526e70SWang Yufen } else if (is_prefix(*argv, "autoattach")) { 165019526e70SWang Yufen auto_attach = true; 165119526e70SWang Yufen NEXT_ARG(); 1652ba6dd679SJakub Kicinski } else { 16533ff5a4dcSJakub Kicinski p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 1654ba6dd679SJakub Kicinski *argv); 16553ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 1656ba6dd679SJakub Kicinski } 1657ba6dd679SJakub Kicinski } 1658ba6dd679SJakub Kicinski 16596b4384ffSQuentin Monnet set_max_rlimit(); 16606b4384ffSQuentin Monnet 1661b59e4ce8SAndrii Nakryiko if (verifier_logs) 1662b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1663b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1664b59e4ce8SAndrii Nakryiko 166532e3e58eSAndrii Nakryiko obj = bpf_object__open_file(file, &open_opts); 1666d1313e01SSahid Orentino Ferdjaoui if (!obj) { 1667c8406848SJakub Kicinski p_err("failed to open object file"); 16683ff5a4dcSJakub Kicinski goto err_free_reuse_maps; 166949a086c2SRoman Gushchin } 167049a086c2SRoman Gushchin 167177380998SStanislav Fomichev bpf_object__for_each_program(pos, obj) { 167232e3e58eSAndrii Nakryiko enum bpf_prog_type prog_type = common_prog_type; 1673c8406848SJakub Kicinski 167432e3e58eSAndrii Nakryiko if (prog_type == BPF_PROG_TYPE_UNSPEC) { 1675fd17e272SAndrii Nakryiko const char *sec_name = bpf_program__section_name(pos); 1676c8406848SJakub Kicinski 16776ae32b29SQuentin Monnet err = get_prog_type_by_name(sec_name, &prog_type, 1678c8406848SJakub Kicinski &expected_attach_type); 1679c76e4c22STaeung Song if (err < 0) 1680c8406848SJakub Kicinski goto err_close_obj; 1681c8406848SJakub Kicinski } 168277380998SStanislav Fomichev 168377380998SStanislav Fomichev bpf_program__set_ifindex(pos, ifindex); 168477380998SStanislav Fomichev bpf_program__set_type(pos, prog_type); 168577380998SStanislav Fomichev bpf_program__set_expected_attach_type(pos, expected_attach_type); 168677380998SStanislav Fomichev } 1687c8406848SJakub Kicinski 16883ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 16893ff5a4dcSJakub Kicinski map_replace_compar); 16903ff5a4dcSJakub Kicinski 16913ff5a4dcSJakub Kicinski /* After the sort maps by name will be first on the list, because they 16923ff5a4dcSJakub Kicinski * have idx == -1. Resolve them. 16933ff5a4dcSJakub Kicinski */ 16943ff5a4dcSJakub Kicinski j = 0; 16953ff5a4dcSJakub Kicinski while (j < old_map_fds && map_replace[j].name) { 16963ff5a4dcSJakub Kicinski i = 0; 1697f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 16983ff5a4dcSJakub Kicinski if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 16993ff5a4dcSJakub Kicinski map_replace[j].idx = i; 17003ff5a4dcSJakub Kicinski break; 17013ff5a4dcSJakub Kicinski } 17023ff5a4dcSJakub Kicinski i++; 17033ff5a4dcSJakub Kicinski } 17043ff5a4dcSJakub Kicinski if (map_replace[j].idx == -1) { 17053ff5a4dcSJakub Kicinski p_err("unable to find map '%s'", map_replace[j].name); 17063ff5a4dcSJakub Kicinski goto err_close_obj; 17073ff5a4dcSJakub Kicinski } 17083ff5a4dcSJakub Kicinski j++; 17093ff5a4dcSJakub Kicinski } 17103ff5a4dcSJakub Kicinski /* Resort if any names were resolved */ 17113ff5a4dcSJakub Kicinski if (j) 17123ff5a4dcSJakub Kicinski qsort(map_replace, old_map_fds, sizeof(*map_replace), 17133ff5a4dcSJakub Kicinski map_replace_compar); 17143ff5a4dcSJakub Kicinski 17153ff5a4dcSJakub Kicinski /* Set ifindex and name reuse */ 17163ff5a4dcSJakub Kicinski j = 0; 17173ff5a4dcSJakub Kicinski idx = 0; 1718f74a53d9SJakub Kicinski bpf_object__for_each_map(map, obj) { 17199855c131SChristy Lee if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 1720c8406848SJakub Kicinski bpf_map__set_ifindex(map, ifindex); 1721c8406848SJakub Kicinski 17223ff5a4dcSJakub Kicinski if (j < old_map_fds && idx == map_replace[j].idx) { 17233ff5a4dcSJakub Kicinski err = bpf_map__reuse_fd(map, map_replace[j++].fd); 17243ff5a4dcSJakub Kicinski if (err) { 17253ff5a4dcSJakub Kicinski p_err("unable to set up map reuse: %d", err); 17263ff5a4dcSJakub Kicinski goto err_close_obj; 17273ff5a4dcSJakub Kicinski } 17283ff5a4dcSJakub Kicinski 17293ff5a4dcSJakub Kicinski /* Next reuse wants to apply to the same map */ 17303ff5a4dcSJakub Kicinski if (j < old_map_fds && map_replace[j].idx == idx) { 17313ff5a4dcSJakub Kicinski p_err("replacement for map idx %d specified more than once", 17323ff5a4dcSJakub Kicinski idx); 17333ff5a4dcSJakub Kicinski goto err_close_obj; 17343ff5a4dcSJakub Kicinski } 17353ff5a4dcSJakub Kicinski } 17363ff5a4dcSJakub Kicinski 17373ff5a4dcSJakub Kicinski idx++; 17383ff5a4dcSJakub Kicinski } 17393ff5a4dcSJakub Kicinski if (j < old_map_fds) { 17403ff5a4dcSJakub Kicinski p_err("map idx '%d' not used", map_replace[j].idx); 17413ff5a4dcSJakub Kicinski goto err_close_obj; 17423ff5a4dcSJakub Kicinski } 17433ff5a4dcSJakub Kicinski 1744b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1745c8406848SJakub Kicinski if (err) { 1746c8406848SJakub Kicinski p_err("failed to load object file"); 1747c8406848SJakub Kicinski goto err_close_obj; 1748c8406848SJakub Kicinski } 1749c8406848SJakub Kicinski 175077380998SStanislav Fomichev err = mount_bpffs_for_pin(pinfile); 175177380998SStanislav Fomichev if (err) 1752bfee71fbSJakub Kicinski goto err_close_obj; 175349a086c2SRoman Gushchin 175477380998SStanislav Fomichev if (first_prog_only) { 17556f2b219bSHengqi Chen prog = bpf_object__next_program(obj, NULL); 175677380998SStanislav Fomichev if (!prog) { 175777380998SStanislav Fomichev p_err("object file doesn't contain any bpf program"); 175877380998SStanislav Fomichev goto err_close_obj; 175977380998SStanislav Fomichev } 176077380998SStanislav Fomichev 176119526e70SWang Yufen if (auto_attach) 176219526e70SWang Yufen err = auto_attach_program(prog, pinfile); 176319526e70SWang Yufen else 176477380998SStanislav Fomichev err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 176577380998SStanislav Fomichev if (err) { 176677380998SStanislav Fomichev p_err("failed to pin program %s", 1767fd17e272SAndrii Nakryiko bpf_program__section_name(prog)); 176877380998SStanislav Fomichev goto err_close_obj; 176977380998SStanislav Fomichev } 177077380998SStanislav Fomichev } else { 177119526e70SWang Yufen if (auto_attach) 177219526e70SWang Yufen err = auto_attach_programs(obj, pinfile); 177319526e70SWang Yufen else 177477380998SStanislav Fomichev err = bpf_object__pin_programs(obj, pinfile); 177577380998SStanislav Fomichev if (err) { 177677380998SStanislav Fomichev p_err("failed to pin all programs"); 177777380998SStanislav Fomichev goto err_close_obj; 177877380998SStanislav Fomichev } 177977380998SStanislav Fomichev } 178077380998SStanislav Fomichev 17813767a94bSStanislav Fomichev if (pinmaps) { 17823767a94bSStanislav Fomichev err = bpf_object__pin_maps(obj, pinmaps); 17833767a94bSStanislav Fomichev if (err) { 17843767a94bSStanislav Fomichev p_err("failed to pin all maps"); 17853767a94bSStanislav Fomichev goto err_unpin; 17863767a94bSStanislav Fomichev } 17873767a94bSStanislav Fomichev } 17883767a94bSStanislav Fomichev 178949a086c2SRoman Gushchin if (json_output) 179049a086c2SRoman Gushchin jsonw_null(json_wtr); 179149a086c2SRoman Gushchin 1792bfee71fbSJakub Kicinski bpf_object__close(obj); 17933ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 17943ff5a4dcSJakub Kicinski close(map_replace[i].fd); 17953ff5a4dcSJakub Kicinski free(map_replace); 1796bfee71fbSJakub Kicinski 179749a086c2SRoman Gushchin return 0; 1798bfee71fbSJakub Kicinski 17993767a94bSStanislav Fomichev err_unpin: 18003767a94bSStanislav Fomichev if (first_prog_only) 18013767a94bSStanislav Fomichev unlink(pinfile); 18023767a94bSStanislav Fomichev else 18033767a94bSStanislav Fomichev bpf_object__unpin_programs(obj, pinfile); 1804bfee71fbSJakub Kicinski err_close_obj: 1805bfee71fbSJakub Kicinski bpf_object__close(obj); 18063ff5a4dcSJakub Kicinski err_free_reuse_maps: 18073ff5a4dcSJakub Kicinski for (i = 0; i < old_map_fds; i++) 18083ff5a4dcSJakub Kicinski close(map_replace[i].fd); 18093ff5a4dcSJakub Kicinski free(map_replace); 1810bfee71fbSJakub Kicinski return -1; 181149a086c2SRoman Gushchin } 181249a086c2SRoman Gushchin 1813d510296dSAlexei Starovoitov static int count_open_fds(void) 1814d510296dSAlexei Starovoitov { 1815d510296dSAlexei Starovoitov DIR *dp = opendir("/proc/self/fd"); 1816d510296dSAlexei Starovoitov struct dirent *de; 1817d510296dSAlexei Starovoitov int cnt = -3; 1818d510296dSAlexei Starovoitov 1819d510296dSAlexei Starovoitov if (!dp) 1820d510296dSAlexei Starovoitov return -1; 1821d510296dSAlexei Starovoitov 1822d510296dSAlexei Starovoitov while ((de = readdir(dp))) 1823d510296dSAlexei Starovoitov cnt++; 1824d510296dSAlexei Starovoitov 1825d510296dSAlexei Starovoitov closedir(dp); 1826d510296dSAlexei Starovoitov return cnt; 1827d510296dSAlexei Starovoitov } 1828d510296dSAlexei Starovoitov 1829d510296dSAlexei Starovoitov static int try_loader(struct gen_loader_opts *gen) 1830d510296dSAlexei Starovoitov { 1831d510296dSAlexei Starovoitov struct bpf_load_and_run_opts opts = {}; 1832d510296dSAlexei Starovoitov struct bpf_loader_ctx *ctx; 1833d510296dSAlexei Starovoitov int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 1834d510296dSAlexei Starovoitov sizeof(struct bpf_prog_desc)); 1835d510296dSAlexei Starovoitov int log_buf_sz = (1u << 24) - 1; 1836d510296dSAlexei Starovoitov int err, fds_before, fd_delta; 1837942df4dcSAlexei Starovoitov char *log_buf = NULL; 1838d510296dSAlexei Starovoitov 1839d510296dSAlexei Starovoitov ctx = alloca(ctx_sz); 1840d510296dSAlexei Starovoitov memset(ctx, 0, ctx_sz); 1841d510296dSAlexei Starovoitov ctx->sz = ctx_sz; 1842942df4dcSAlexei Starovoitov if (verifier_logs) { 1843942df4dcSAlexei Starovoitov ctx->log_level = 1 + 2 + 4; 1844d510296dSAlexei Starovoitov ctx->log_size = log_buf_sz; 1845d510296dSAlexei Starovoitov log_buf = malloc(log_buf_sz); 1846d510296dSAlexei Starovoitov if (!log_buf) 1847d510296dSAlexei Starovoitov return -ENOMEM; 1848d510296dSAlexei Starovoitov ctx->log_buf = (long) log_buf; 1849942df4dcSAlexei Starovoitov } 1850d510296dSAlexei Starovoitov opts.ctx = ctx; 1851d510296dSAlexei Starovoitov opts.data = gen->data; 1852d510296dSAlexei Starovoitov opts.data_sz = gen->data_sz; 1853d510296dSAlexei Starovoitov opts.insns = gen->insns; 1854d510296dSAlexei Starovoitov opts.insns_sz = gen->insns_sz; 1855d510296dSAlexei Starovoitov fds_before = count_open_fds(); 1856d510296dSAlexei Starovoitov err = bpf_load_and_run(&opts); 1857d510296dSAlexei Starovoitov fd_delta = count_open_fds() - fds_before; 1858942df4dcSAlexei Starovoitov if (err < 0 || verifier_logs) { 1859d510296dSAlexei Starovoitov fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 1860942df4dcSAlexei Starovoitov if (fd_delta && err < 0) 1861d510296dSAlexei Starovoitov fprintf(stderr, "loader prog leaked %d FDs\n", 1862d510296dSAlexei Starovoitov fd_delta); 1863d510296dSAlexei Starovoitov } 1864d510296dSAlexei Starovoitov free(log_buf); 1865d510296dSAlexei Starovoitov return err; 1866d510296dSAlexei Starovoitov } 1867d510296dSAlexei Starovoitov 1868d510296dSAlexei Starovoitov static int do_loader(int argc, char **argv) 1869d510296dSAlexei Starovoitov { 1870d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 1871d510296dSAlexei Starovoitov DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 1872d510296dSAlexei Starovoitov struct bpf_object *obj; 1873d510296dSAlexei Starovoitov const char *file; 1874d510296dSAlexei Starovoitov int err = 0; 1875d510296dSAlexei Starovoitov 1876d510296dSAlexei Starovoitov if (!REQ_ARGS(1)) 1877d510296dSAlexei Starovoitov return -1; 1878d510296dSAlexei Starovoitov file = GET_ARG(); 1879d510296dSAlexei Starovoitov 1880b59e4ce8SAndrii Nakryiko if (verifier_logs) 1881b59e4ce8SAndrii Nakryiko /* log_level1 + log_level2 + stats, but not stable UAPI */ 1882b59e4ce8SAndrii Nakryiko open_opts.kernel_log_level = 1 + 2 + 4; 1883b59e4ce8SAndrii Nakryiko 1884d510296dSAlexei Starovoitov obj = bpf_object__open_file(file, &open_opts); 1885d1313e01SSahid Orentino Ferdjaoui if (!obj) { 1886d510296dSAlexei Starovoitov p_err("failed to open object file"); 1887d510296dSAlexei Starovoitov goto err_close_obj; 1888d510296dSAlexei Starovoitov } 1889d510296dSAlexei Starovoitov 1890d510296dSAlexei Starovoitov err = bpf_object__gen_loader(obj, &gen); 1891d510296dSAlexei Starovoitov if (err) 1892d510296dSAlexei Starovoitov goto err_close_obj; 1893d510296dSAlexei Starovoitov 1894b59e4ce8SAndrii Nakryiko err = bpf_object__load(obj); 1895d510296dSAlexei Starovoitov if (err) { 1896d510296dSAlexei Starovoitov p_err("failed to load object file"); 1897d510296dSAlexei Starovoitov goto err_close_obj; 1898d510296dSAlexei Starovoitov } 1899d510296dSAlexei Starovoitov 1900d510296dSAlexei Starovoitov if (verifier_logs) { 1901d510296dSAlexei Starovoitov struct dump_data dd = {}; 1902d510296dSAlexei Starovoitov 1903d510296dSAlexei Starovoitov kernel_syms_load(&dd); 1904d510296dSAlexei Starovoitov dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 1905d510296dSAlexei Starovoitov kernel_syms_destroy(&dd); 1906d510296dSAlexei Starovoitov } 1907d510296dSAlexei Starovoitov err = try_loader(&gen); 1908d510296dSAlexei Starovoitov err_close_obj: 1909d510296dSAlexei Starovoitov bpf_object__close(obj); 1910d510296dSAlexei Starovoitov return err; 1911d510296dSAlexei Starovoitov } 1912d510296dSAlexei Starovoitov 191377380998SStanislav Fomichev static int do_load(int argc, char **argv) 191477380998SStanislav Fomichev { 1915d510296dSAlexei Starovoitov if (use_loader) 1916d510296dSAlexei Starovoitov return do_loader(argc, argv); 191777380998SStanislav Fomichev return load_with_options(argc, argv, true); 191877380998SStanislav Fomichev } 191977380998SStanislav Fomichev 192077380998SStanislav Fomichev static int do_loadall(int argc, char **argv) 192177380998SStanislav Fomichev { 192277380998SStanislav Fomichev return load_with_options(argc, argv, false); 192377380998SStanislav Fomichev } 192477380998SStanislav Fomichev 192547c09d6aSSong Liu #ifdef BPFTOOL_WITHOUT_SKELETONS 192647c09d6aSSong Liu 192747c09d6aSSong Liu static int do_profile(int argc, char **argv) 192847c09d6aSSong Liu { 192914e5728fSSong Liu p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 193047c09d6aSSong Liu return 0; 193147c09d6aSSong Liu } 193247c09d6aSSong Liu 193347c09d6aSSong Liu #else /* BPFTOOL_WITHOUT_SKELETONS */ 193447c09d6aSSong Liu 193547c09d6aSSong Liu #include "profiler.skel.h" 193647c09d6aSSong Liu 193747c09d6aSSong Liu struct profile_metric { 193847c09d6aSSong Liu const char *name; 193947c09d6aSSong Liu struct bpf_perf_event_value val; 194047c09d6aSSong Liu struct perf_event_attr attr; 194147c09d6aSSong Liu bool selected; 194247c09d6aSSong Liu 194347c09d6aSSong Liu /* calculate ratios like instructions per cycle */ 194447c09d6aSSong Liu const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 194547c09d6aSSong Liu const char *ratio_desc; 194647c09d6aSSong Liu const float ratio_mul; 194747c09d6aSSong Liu } metrics[] = { 194847c09d6aSSong Liu { 194947c09d6aSSong Liu .name = "cycles", 195047c09d6aSSong Liu .attr = { 195147c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 195247c09d6aSSong Liu .config = PERF_COUNT_HW_CPU_CYCLES, 195347c09d6aSSong Liu .exclude_user = 1, 195447c09d6aSSong Liu }, 195547c09d6aSSong Liu }, 195647c09d6aSSong Liu { 195747c09d6aSSong Liu .name = "instructions", 195847c09d6aSSong Liu .attr = { 195947c09d6aSSong Liu .type = PERF_TYPE_HARDWARE, 196047c09d6aSSong Liu .config = PERF_COUNT_HW_INSTRUCTIONS, 196147c09d6aSSong Liu .exclude_user = 1, 196247c09d6aSSong Liu }, 196347c09d6aSSong Liu .ratio_metric = 1, 196447c09d6aSSong Liu .ratio_desc = "insns per cycle", 196547c09d6aSSong Liu .ratio_mul = 1.0, 196647c09d6aSSong Liu }, 196747c09d6aSSong Liu { 196847c09d6aSSong Liu .name = "l1d_loads", 196947c09d6aSSong Liu .attr = { 197047c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 197147c09d6aSSong Liu .config = 197247c09d6aSSong Liu PERF_COUNT_HW_CACHE_L1D | 197347c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 197447c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 197547c09d6aSSong Liu .exclude_user = 1, 197647c09d6aSSong Liu }, 197747c09d6aSSong Liu }, 197847c09d6aSSong Liu { 197947c09d6aSSong Liu .name = "llc_misses", 198047c09d6aSSong Liu .attr = { 198147c09d6aSSong Liu .type = PERF_TYPE_HW_CACHE, 198247c09d6aSSong Liu .config = 198347c09d6aSSong Liu PERF_COUNT_HW_CACHE_LL | 198447c09d6aSSong Liu (PERF_COUNT_HW_CACHE_OP_READ << 8) | 198547c09d6aSSong Liu (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 198647c09d6aSSong Liu .exclude_user = 1 198747c09d6aSSong Liu }, 198847c09d6aSSong Liu .ratio_metric = 2, 198947c09d6aSSong Liu .ratio_desc = "LLC misses per million insns", 199047c09d6aSSong Liu .ratio_mul = 1e6, 199147c09d6aSSong Liu }, 1992450d060eSYonghong Song { 1993450d060eSYonghong Song .name = "itlb_misses", 1994450d060eSYonghong Song .attr = { 1995450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 1996450d060eSYonghong Song .config = 1997450d060eSYonghong Song PERF_COUNT_HW_CACHE_ITLB | 1998450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 1999450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 2000450d060eSYonghong Song .exclude_user = 1 2001450d060eSYonghong Song }, 2002450d060eSYonghong Song .ratio_metric = 2, 2003450d060eSYonghong Song .ratio_desc = "itlb misses per million insns", 2004450d060eSYonghong Song .ratio_mul = 1e6, 2005450d060eSYonghong Song }, 2006450d060eSYonghong Song { 2007450d060eSYonghong Song .name = "dtlb_misses", 2008450d060eSYonghong Song .attr = { 2009450d060eSYonghong Song .type = PERF_TYPE_HW_CACHE, 2010450d060eSYonghong Song .config = 2011450d060eSYonghong Song PERF_COUNT_HW_CACHE_DTLB | 2012450d060eSYonghong Song (PERF_COUNT_HW_CACHE_OP_READ << 8) | 2013450d060eSYonghong Song (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 2014450d060eSYonghong Song .exclude_user = 1 2015450d060eSYonghong Song }, 2016450d060eSYonghong Song .ratio_metric = 2, 2017450d060eSYonghong Song .ratio_desc = "dtlb misses per million insns", 2018450d060eSYonghong Song .ratio_mul = 1e6, 2019450d060eSYonghong Song }, 202047c09d6aSSong Liu }; 202147c09d6aSSong Liu 202247c09d6aSSong Liu static __u64 profile_total_count; 202347c09d6aSSong Liu 202447c09d6aSSong Liu #define MAX_NUM_PROFILE_METRICS 4 202547c09d6aSSong Liu 202647c09d6aSSong Liu static int profile_parse_metrics(int argc, char **argv) 202747c09d6aSSong Liu { 202847c09d6aSSong Liu unsigned int metric_cnt; 202947c09d6aSSong Liu int selected_cnt = 0; 203047c09d6aSSong Liu unsigned int i; 203147c09d6aSSong Liu 20325eff8c18SRongguang Wei metric_cnt = ARRAY_SIZE(metrics); 203347c09d6aSSong Liu 203447c09d6aSSong Liu while (argc > 0) { 203547c09d6aSSong Liu for (i = 0; i < metric_cnt; i++) { 203647c09d6aSSong Liu if (is_prefix(argv[0], metrics[i].name)) { 203747c09d6aSSong Liu if (!metrics[i].selected) 203847c09d6aSSong Liu selected_cnt++; 203947c09d6aSSong Liu metrics[i].selected = true; 204047c09d6aSSong Liu break; 204147c09d6aSSong Liu } 204247c09d6aSSong Liu } 204347c09d6aSSong Liu if (i == metric_cnt) { 204447c09d6aSSong Liu p_err("unknown metric %s", argv[0]); 204547c09d6aSSong Liu return -1; 204647c09d6aSSong Liu } 204747c09d6aSSong Liu NEXT_ARG(); 204847c09d6aSSong Liu } 204947c09d6aSSong Liu if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 205047c09d6aSSong Liu p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 205147c09d6aSSong Liu selected_cnt, MAX_NUM_PROFILE_METRICS); 205247c09d6aSSong Liu return -1; 205347c09d6aSSong Liu } 205447c09d6aSSong Liu return selected_cnt; 205547c09d6aSSong Liu } 205647c09d6aSSong Liu 205747c09d6aSSong Liu static void profile_read_values(struct profiler_bpf *obj) 205847c09d6aSSong Liu { 205947c09d6aSSong Liu __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 206047c09d6aSSong Liu int reading_map_fd, count_map_fd; 206147c09d6aSSong Liu __u64 counts[num_cpu]; 206247c09d6aSSong Liu __u32 key = 0; 206347c09d6aSSong Liu int err; 206447c09d6aSSong Liu 206547c09d6aSSong Liu reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 206647c09d6aSSong Liu count_map_fd = bpf_map__fd(obj->maps.counts); 206747c09d6aSSong Liu if (reading_map_fd < 0 || count_map_fd < 0) { 206847c09d6aSSong Liu p_err("failed to get fd for map"); 206947c09d6aSSong Liu return; 207047c09d6aSSong Liu } 207147c09d6aSSong Liu 207247c09d6aSSong Liu err = bpf_map_lookup_elem(count_map_fd, &key, counts); 207347c09d6aSSong Liu if (err) { 207447c09d6aSSong Liu p_err("failed to read count_map: %s", strerror(errno)); 207547c09d6aSSong Liu return; 207647c09d6aSSong Liu } 207747c09d6aSSong Liu 207847c09d6aSSong Liu profile_total_count = 0; 207947c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) 208047c09d6aSSong Liu profile_total_count += counts[cpu]; 208147c09d6aSSong Liu 208247c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 208347c09d6aSSong Liu struct bpf_perf_event_value values[num_cpu]; 208447c09d6aSSong Liu 208547c09d6aSSong Liu if (!metrics[m].selected) 208647c09d6aSSong Liu continue; 208747c09d6aSSong Liu 208847c09d6aSSong Liu err = bpf_map_lookup_elem(reading_map_fd, &key, values); 208947c09d6aSSong Liu if (err) { 209047c09d6aSSong Liu p_err("failed to read reading_map: %s", 209147c09d6aSSong Liu strerror(errno)); 209247c09d6aSSong Liu return; 209347c09d6aSSong Liu } 209447c09d6aSSong Liu for (cpu = 0; cpu < num_cpu; cpu++) { 209547c09d6aSSong Liu metrics[m].val.counter += values[cpu].counter; 209647c09d6aSSong Liu metrics[m].val.enabled += values[cpu].enabled; 209747c09d6aSSong Liu metrics[m].val.running += values[cpu].running; 209847c09d6aSSong Liu } 209947c09d6aSSong Liu key++; 210047c09d6aSSong Liu } 210147c09d6aSSong Liu } 210247c09d6aSSong Liu 210347c09d6aSSong Liu static void profile_print_readings_json(void) 210447c09d6aSSong Liu { 210547c09d6aSSong Liu __u32 m; 210647c09d6aSSong Liu 210747c09d6aSSong Liu jsonw_start_array(json_wtr); 210847c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 210947c09d6aSSong Liu if (!metrics[m].selected) 211047c09d6aSSong Liu continue; 211147c09d6aSSong Liu jsonw_start_object(json_wtr); 211247c09d6aSSong Liu jsonw_string_field(json_wtr, "metric", metrics[m].name); 211347c09d6aSSong Liu jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 211447c09d6aSSong Liu jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 211547c09d6aSSong Liu jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 211647c09d6aSSong Liu jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 211747c09d6aSSong Liu 211847c09d6aSSong Liu jsonw_end_object(json_wtr); 211947c09d6aSSong Liu } 212047c09d6aSSong Liu jsonw_end_array(json_wtr); 212147c09d6aSSong Liu } 212247c09d6aSSong Liu 212347c09d6aSSong Liu static void profile_print_readings_plain(void) 212447c09d6aSSong Liu { 212547c09d6aSSong Liu __u32 m; 212647c09d6aSSong Liu 212747c09d6aSSong Liu printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 212847c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 212947c09d6aSSong Liu struct bpf_perf_event_value *val = &metrics[m].val; 213047c09d6aSSong Liu int r; 213147c09d6aSSong Liu 213247c09d6aSSong Liu if (!metrics[m].selected) 213347c09d6aSSong Liu continue; 213447c09d6aSSong Liu printf("%18llu %-20s", val->counter, metrics[m].name); 213547c09d6aSSong Liu 213647c09d6aSSong Liu r = metrics[m].ratio_metric - 1; 213747c09d6aSSong Liu if (r >= 0 && metrics[r].selected && 213847c09d6aSSong Liu metrics[r].val.counter > 0) { 213947c09d6aSSong Liu printf("# %8.2f %-30s", 214047c09d6aSSong Liu val->counter * metrics[m].ratio_mul / 214147c09d6aSSong Liu metrics[r].val.counter, 214247c09d6aSSong Liu metrics[m].ratio_desc); 214347c09d6aSSong Liu } else { 214447c09d6aSSong Liu printf("%-41s", ""); 214547c09d6aSSong Liu } 214647c09d6aSSong Liu 214747c09d6aSSong Liu if (val->enabled > val->running) 214847c09d6aSSong Liu printf("(%4.2f%%)", 214947c09d6aSSong Liu val->running * 100.0 / val->enabled); 215047c09d6aSSong Liu printf("\n"); 215147c09d6aSSong Liu } 215247c09d6aSSong Liu } 215347c09d6aSSong Liu 215447c09d6aSSong Liu static void profile_print_readings(void) 215547c09d6aSSong Liu { 215647c09d6aSSong Liu if (json_output) 215747c09d6aSSong Liu profile_print_readings_json(); 215847c09d6aSSong Liu else 215947c09d6aSSong Liu profile_print_readings_plain(); 216047c09d6aSSong Liu } 216147c09d6aSSong Liu 216247c09d6aSSong Liu static char *profile_target_name(int tgt_fd) 216347c09d6aSSong Liu { 2164c59765cfSDave Marchevsky struct bpf_func_info func_info; 2165c59765cfSDave Marchevsky struct bpf_prog_info info = {}; 2166c59765cfSDave Marchevsky __u32 info_len = sizeof(info); 216747c09d6aSSong Liu const struct btf_type *t; 2168c59765cfSDave Marchevsky __u32 func_info_rec_size; 2169369e955bSQuentin Monnet struct btf *btf = NULL; 217047c09d6aSSong Liu char *name = NULL; 2171c59765cfSDave Marchevsky int err; 217247c09d6aSSong Liu 2173*38f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len); 2174c59765cfSDave Marchevsky if (err) { 2175*38f0408eSIlya Leoshkevich p_err("failed to get info for prog FD %d", tgt_fd); 2176c59765cfSDave Marchevsky goto out; 217747c09d6aSSong Liu } 217847c09d6aSSong Liu 2179c59765cfSDave Marchevsky if (info.btf_id == 0) { 218047c09d6aSSong Liu p_err("prog FD %d doesn't have valid btf", tgt_fd); 218147c09d6aSSong Liu goto out; 218247c09d6aSSong Liu } 218347c09d6aSSong Liu 2184c59765cfSDave Marchevsky func_info_rec_size = info.func_info_rec_size; 2185c59765cfSDave Marchevsky if (info.nr_func_info == 0) { 2186*38f0408eSIlya Leoshkevich p_err("found 0 func_info for prog FD %d", tgt_fd); 2187c59765cfSDave Marchevsky goto out; 2188c59765cfSDave Marchevsky } 2189c59765cfSDave Marchevsky 2190c59765cfSDave Marchevsky memset(&info, 0, sizeof(info)); 2191c59765cfSDave Marchevsky info.nr_func_info = 1; 2192c59765cfSDave Marchevsky info.func_info_rec_size = func_info_rec_size; 2193c59765cfSDave Marchevsky info.func_info = ptr_to_u64(&func_info); 2194c59765cfSDave Marchevsky 2195*38f0408eSIlya Leoshkevich err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len); 2196c59765cfSDave Marchevsky if (err) { 2197c59765cfSDave Marchevsky p_err("failed to get func_info for prog FD %d", tgt_fd); 2198c59765cfSDave Marchevsky goto out; 2199c59765cfSDave Marchevsky } 2200c59765cfSDave Marchevsky 2201c59765cfSDave Marchevsky btf = btf__load_from_kernel_by_id(info.btf_id); 2202d1313e01SSahid Orentino Ferdjaoui if (!btf) { 220386f4b7f2SQuentin Monnet p_err("failed to load btf for prog FD %d", tgt_fd); 220486f4b7f2SQuentin Monnet goto out; 220586f4b7f2SQuentin Monnet } 220686f4b7f2SQuentin Monnet 2207c59765cfSDave Marchevsky t = btf__type_by_id(btf, func_info.type_id); 220847c09d6aSSong Liu if (!t) { 220947c09d6aSSong Liu p_err("btf %d doesn't have type %d", 2210c59765cfSDave Marchevsky info.btf_id, func_info.type_id); 221147c09d6aSSong Liu goto out; 221247c09d6aSSong Liu } 221347c09d6aSSong Liu name = strdup(btf__name_by_offset(btf, t->name_off)); 221447c09d6aSSong Liu out: 2215369e955bSQuentin Monnet btf__free(btf); 221647c09d6aSSong Liu return name; 221747c09d6aSSong Liu } 221847c09d6aSSong Liu 221947c09d6aSSong Liu static struct profiler_bpf *profile_obj; 222047c09d6aSSong Liu static int profile_tgt_fd = -1; 222147c09d6aSSong Liu static char *profile_tgt_name; 222247c09d6aSSong Liu static int *profile_perf_events; 222347c09d6aSSong Liu static int profile_perf_event_cnt; 222447c09d6aSSong Liu 222547c09d6aSSong Liu static void profile_close_perf_events(struct profiler_bpf *obj) 222647c09d6aSSong Liu { 222747c09d6aSSong Liu int i; 222847c09d6aSSong Liu 222947c09d6aSSong Liu for (i = profile_perf_event_cnt - 1; i >= 0; i--) 223047c09d6aSSong Liu close(profile_perf_events[i]); 223147c09d6aSSong Liu 223247c09d6aSSong Liu free(profile_perf_events); 223347c09d6aSSong Liu profile_perf_event_cnt = 0; 223447c09d6aSSong Liu } 223547c09d6aSSong Liu 2236377c16faSTonghao Zhang static int profile_open_perf_event(int mid, int cpu, int map_fd) 2237377c16faSTonghao Zhang { 2238377c16faSTonghao Zhang int pmu_fd; 2239377c16faSTonghao Zhang 2240377c16faSTonghao Zhang pmu_fd = syscall(__NR_perf_event_open, &metrics[mid].attr, 2241377c16faSTonghao Zhang -1 /*pid*/, cpu, -1 /*group_fd*/, 0); 2242377c16faSTonghao Zhang if (pmu_fd < 0) { 2243377c16faSTonghao Zhang if (errno == ENODEV) { 2244377c16faSTonghao Zhang p_info("cpu %d may be offline, skip %s profiling.", 2245377c16faSTonghao Zhang cpu, metrics[mid].name); 2246377c16faSTonghao Zhang profile_perf_event_cnt++; 2247377c16faSTonghao Zhang return 0; 2248377c16faSTonghao Zhang } 2249377c16faSTonghao Zhang return -1; 2250377c16faSTonghao Zhang } 2251377c16faSTonghao Zhang 2252377c16faSTonghao Zhang if (bpf_map_update_elem(map_fd, 2253377c16faSTonghao Zhang &profile_perf_event_cnt, 2254377c16faSTonghao Zhang &pmu_fd, BPF_ANY) || 2255377c16faSTonghao Zhang ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 2256377c16faSTonghao Zhang close(pmu_fd); 2257377c16faSTonghao Zhang return -1; 2258377c16faSTonghao Zhang } 2259377c16faSTonghao Zhang 2260377c16faSTonghao Zhang profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 2261377c16faSTonghao Zhang return 0; 2262377c16faSTonghao Zhang } 2263377c16faSTonghao Zhang 226447c09d6aSSong Liu static int profile_open_perf_events(struct profiler_bpf *obj) 226547c09d6aSSong Liu { 226647c09d6aSSong Liu unsigned int cpu, m; 2267377c16faSTonghao Zhang int map_fd; 226847c09d6aSSong Liu 226947c09d6aSSong Liu profile_perf_events = calloc( 227047c09d6aSSong Liu sizeof(int), obj->rodata->num_cpu * obj->rodata->num_metric); 227147c09d6aSSong Liu if (!profile_perf_events) { 227247c09d6aSSong Liu p_err("failed to allocate memory for perf_event array: %s", 227347c09d6aSSong Liu strerror(errno)); 227447c09d6aSSong Liu return -1; 227547c09d6aSSong Liu } 227647c09d6aSSong Liu map_fd = bpf_map__fd(obj->maps.events); 227747c09d6aSSong Liu if (map_fd < 0) { 227847c09d6aSSong Liu p_err("failed to get fd for events map"); 227947c09d6aSSong Liu return -1; 228047c09d6aSSong Liu } 228147c09d6aSSong Liu 228247c09d6aSSong Liu for (m = 0; m < ARRAY_SIZE(metrics); m++) { 228347c09d6aSSong Liu if (!metrics[m].selected) 228447c09d6aSSong Liu continue; 228547c09d6aSSong Liu for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 2286377c16faSTonghao Zhang if (profile_open_perf_event(m, cpu, map_fd)) { 228747c09d6aSSong Liu p_err("failed to create event %s on cpu %d", 228847c09d6aSSong Liu metrics[m].name, cpu); 228947c09d6aSSong Liu return -1; 229047c09d6aSSong Liu } 229147c09d6aSSong Liu } 229247c09d6aSSong Liu } 229347c09d6aSSong Liu return 0; 229447c09d6aSSong Liu } 229547c09d6aSSong Liu 229647c09d6aSSong Liu static void profile_print_and_cleanup(void) 229747c09d6aSSong Liu { 229847c09d6aSSong Liu profile_close_perf_events(profile_obj); 229947c09d6aSSong Liu profile_read_values(profile_obj); 230047c09d6aSSong Liu profile_print_readings(); 230147c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 230247c09d6aSSong Liu 230347c09d6aSSong Liu close(profile_tgt_fd); 230447c09d6aSSong Liu free(profile_tgt_name); 230547c09d6aSSong Liu } 230647c09d6aSSong Liu 230747c09d6aSSong Liu static void int_exit(int signo) 230847c09d6aSSong Liu { 230947c09d6aSSong Liu profile_print_and_cleanup(); 231047c09d6aSSong Liu exit(0); 231147c09d6aSSong Liu } 231247c09d6aSSong Liu 231347c09d6aSSong Liu static int do_profile(int argc, char **argv) 231447c09d6aSSong Liu { 231547c09d6aSSong Liu int num_metric, num_cpu, err = -1; 231647c09d6aSSong Liu struct bpf_program *prog; 231747c09d6aSSong Liu unsigned long duration; 231847c09d6aSSong Liu char *endptr; 231947c09d6aSSong Liu 232047c09d6aSSong Liu /* we at least need two args for the prog and one metric */ 232147c09d6aSSong Liu if (!REQ_ARGS(3)) 232247c09d6aSSong Liu return -EINVAL; 232347c09d6aSSong Liu 232447c09d6aSSong Liu /* parse target fd */ 232547c09d6aSSong Liu profile_tgt_fd = prog_parse_fd(&argc, &argv); 232647c09d6aSSong Liu if (profile_tgt_fd < 0) { 232747c09d6aSSong Liu p_err("failed to parse fd"); 232847c09d6aSSong Liu return -1; 232947c09d6aSSong Liu } 233047c09d6aSSong Liu 233147c09d6aSSong Liu /* parse profiling optional duration */ 233247c09d6aSSong Liu if (argc > 2 && is_prefix(argv[0], "duration")) { 233347c09d6aSSong Liu NEXT_ARG(); 233447c09d6aSSong Liu duration = strtoul(*argv, &endptr, 0); 233547c09d6aSSong Liu if (*endptr) 233647c09d6aSSong Liu usage(); 233747c09d6aSSong Liu NEXT_ARG(); 233847c09d6aSSong Liu } else { 233947c09d6aSSong Liu duration = UINT_MAX; 234047c09d6aSSong Liu } 234147c09d6aSSong Liu 234247c09d6aSSong Liu num_metric = profile_parse_metrics(argc, argv); 234347c09d6aSSong Liu if (num_metric <= 0) 234447c09d6aSSong Liu goto out; 234547c09d6aSSong Liu 234647c09d6aSSong Liu num_cpu = libbpf_num_possible_cpus(); 234747c09d6aSSong Liu if (num_cpu <= 0) { 234847c09d6aSSong Liu p_err("failed to identify number of CPUs"); 234947c09d6aSSong Liu goto out; 235047c09d6aSSong Liu } 235147c09d6aSSong Liu 235247c09d6aSSong Liu profile_obj = profiler_bpf__open(); 235347c09d6aSSong Liu if (!profile_obj) { 235447c09d6aSSong Liu p_err("failed to open and/or load BPF object"); 235547c09d6aSSong Liu goto out; 235647c09d6aSSong Liu } 235747c09d6aSSong Liu 235847c09d6aSSong Liu profile_obj->rodata->num_cpu = num_cpu; 235947c09d6aSSong Liu profile_obj->rodata->num_metric = num_metric; 236047c09d6aSSong Liu 236147c09d6aSSong Liu /* adjust map sizes */ 236239748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu); 236339748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric); 236439748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric); 236539748db1SAndrii Nakryiko bpf_map__set_max_entries(profile_obj->maps.counts, 1); 236647c09d6aSSong Liu 236747c09d6aSSong Liu /* change target name */ 236847c09d6aSSong Liu profile_tgt_name = profile_target_name(profile_tgt_fd); 236947c09d6aSSong Liu if (!profile_tgt_name) 237047c09d6aSSong Liu goto out; 237147c09d6aSSong Liu 237247c09d6aSSong Liu bpf_object__for_each_program(prog, profile_obj->obj) { 237347c09d6aSSong Liu err = bpf_program__set_attach_target(prog, profile_tgt_fd, 237447c09d6aSSong Liu profile_tgt_name); 237547c09d6aSSong Liu if (err) { 237647c09d6aSSong Liu p_err("failed to set attach target\n"); 237747c09d6aSSong Liu goto out; 237847c09d6aSSong Liu } 237947c09d6aSSong Liu } 238047c09d6aSSong Liu 23816b4384ffSQuentin Monnet set_max_rlimit(); 238247c09d6aSSong Liu err = profiler_bpf__load(profile_obj); 238347c09d6aSSong Liu if (err) { 238447c09d6aSSong Liu p_err("failed to load profile_obj"); 238547c09d6aSSong Liu goto out; 238647c09d6aSSong Liu } 238747c09d6aSSong Liu 238847c09d6aSSong Liu err = profile_open_perf_events(profile_obj); 238947c09d6aSSong Liu if (err) 239047c09d6aSSong Liu goto out; 239147c09d6aSSong Liu 239247c09d6aSSong Liu err = profiler_bpf__attach(profile_obj); 239347c09d6aSSong Liu if (err) { 239447c09d6aSSong Liu p_err("failed to attach profile_obj"); 239547c09d6aSSong Liu goto out; 239647c09d6aSSong Liu } 239747c09d6aSSong Liu signal(SIGINT, int_exit); 239847c09d6aSSong Liu 239947c09d6aSSong Liu sleep(duration); 240047c09d6aSSong Liu profile_print_and_cleanup(); 240147c09d6aSSong Liu return 0; 240247c09d6aSSong Liu 240347c09d6aSSong Liu out: 240447c09d6aSSong Liu profile_close_perf_events(profile_obj); 240547c09d6aSSong Liu if (profile_obj) 240647c09d6aSSong Liu profiler_bpf__destroy(profile_obj); 240747c09d6aSSong Liu close(profile_tgt_fd); 240847c09d6aSSong Liu free(profile_tgt_name); 240947c09d6aSSong Liu return err; 241047c09d6aSSong Liu } 241147c09d6aSSong Liu 241247c09d6aSSong Liu #endif /* BPFTOOL_WITHOUT_SKELETONS */ 241347c09d6aSSong Liu 241471bb428fSJakub Kicinski static int do_help(int argc, char **argv) 241571bb428fSJakub Kicinski { 2416004b45c0SQuentin Monnet if (json_output) { 2417004b45c0SQuentin Monnet jsonw_null(json_wtr); 2418004b45c0SQuentin Monnet return 0; 2419004b45c0SQuentin Monnet } 2420004b45c0SQuentin Monnet 242171bb428fSJakub Kicinski fprintf(stderr, 242290040351SQuentin Monnet "Usage: %1$s %2$s { show | list } [PROG]\n" 242390040351SQuentin Monnet " %1$s %2$s dump xlated PROG [{ file FILE | opcodes | visual | linum }]\n" 242490040351SQuentin Monnet " %1$s %2$s dump jited PROG [{ file FILE | opcodes | linum }]\n" 242590040351SQuentin Monnet " %1$s %2$s pin PROG FILE\n" 242690040351SQuentin Monnet " %1$s %2$s { load | loadall } OBJ PATH \\\n" 242777380998SStanislav Fomichev " [type TYPE] [dev NAME] \\\n" 24283767a94bSStanislav Fomichev " [map { idx IDX | name NAME } MAP]\\\n" 24293767a94bSStanislav Fomichev " [pinmaps MAP_DIR]\n" 243019526e70SWang Yufen " [autoattach]\n" 243190040351SQuentin Monnet " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 243290040351SQuentin Monnet " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 243390040351SQuentin Monnet " %1$s %2$s run PROG \\\n" 2434ba95c745SQuentin Monnet " data_in FILE \\\n" 2435ba95c745SQuentin Monnet " [data_out FILE [data_size_out L]] \\\n" 2436ba95c745SQuentin Monnet " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 2437ba95c745SQuentin Monnet " [repeat N]\n" 243890040351SQuentin Monnet " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 243990040351SQuentin Monnet " %1$s %2$s tracelog\n" 244090040351SQuentin Monnet " %1$s %2$s help\n" 244171bb428fSJakub Kicinski "\n" 24423ff5a4dcSJakub Kicinski " " HELP_SPEC_MAP "\n" 244371bb428fSJakub Kicinski " " HELP_SPEC_PROGRAM "\n" 244449f2cba3SJakub Kicinski " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 244549f2cba3SJakub Kicinski " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 244649f2cba3SJakub Kicinski " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 244749f2cba3SJakub Kicinski " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 2448f25377eeSAndrey Ignatov " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 244949f2cba3SJakub Kicinski " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 245049f2cba3SJakub Kicinski " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 245105ee19c1SDaniel Borkmann " cgroup/getpeername4 | cgroup/getpeername6 |\n" 245205ee19c1SDaniel Borkmann " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 245305ee19c1SDaniel Borkmann " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 2454a8deba85SLiu Jian " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 245593a3545dSJakub Sitnicki " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 24561ba5ad36SDaniel Müller " ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n" 24571ba5ad36SDaniel Müller " sk_skb_stream_parser | flow_dissector }\n" 2458450d060eSYonghong Song " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 2459c07ba629SQuentin Monnet " " HELP_SPEC_OPTIONS " |\n" 24608cc8c635SQuentin Monnet " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 24618cc8c635SQuentin Monnet " {-L|--use-loader} }\n" 246271bb428fSJakub Kicinski "", 246390040351SQuentin Monnet bin_name, argv[-2]); 246471bb428fSJakub Kicinski 246571bb428fSJakub Kicinski return 0; 246671bb428fSJakub Kicinski } 246771bb428fSJakub Kicinski 246871bb428fSJakub Kicinski static const struct cmd cmds[] = { 246971bb428fSJakub Kicinski { "show", do_show }, 24706ebe6dbdSJakub Kicinski { "list", do_show }, 24719f606179SQuentin Monnet { "help", do_help }, 247271bb428fSJakub Kicinski { "dump", do_dump }, 247371bb428fSJakub Kicinski { "pin", do_pin }, 247449a086c2SRoman Gushchin { "load", do_load }, 247577380998SStanislav Fomichev { "loadall", do_loadall }, 2476b7d3826cSJohn Fastabend { "attach", do_attach }, 2477b7d3826cSJohn Fastabend { "detach", do_detach }, 247830da46b5SQuentin Monnet { "tracelog", do_tracelog }, 2479ba95c745SQuentin Monnet { "run", do_run }, 248047c09d6aSSong Liu { "profile", do_profile }, 248171bb428fSJakub Kicinski { 0 } 248271bb428fSJakub Kicinski }; 248371bb428fSJakub Kicinski 248471bb428fSJakub Kicinski int do_prog(int argc, char **argv) 248571bb428fSJakub Kicinski { 248671bb428fSJakub Kicinski return cmd_select(cmds, argc, argv, do_help); 248771bb428fSJakub Kicinski } 2488