162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#ifndef _GNU_SOURCE 562306a36Sopenharmony_ci#define _GNU_SOURCE 662306a36Sopenharmony_ci#endif 762306a36Sopenharmony_ci#include <errno.h> 862306a36Sopenharmony_ci#include <fcntl.h> 962306a36Sopenharmony_ci#include <signal.h> 1062306a36Sopenharmony_ci#include <stdarg.h> 1162306a36Sopenharmony_ci#include <stdio.h> 1262306a36Sopenharmony_ci#include <stdlib.h> 1362306a36Sopenharmony_ci#include <string.h> 1462306a36Sopenharmony_ci#include <time.h> 1562306a36Sopenharmony_ci#include <unistd.h> 1662306a36Sopenharmony_ci#include <net/if.h> 1762306a36Sopenharmony_ci#include <sys/ioctl.h> 1862306a36Sopenharmony_ci#include <sys/types.h> 1962306a36Sopenharmony_ci#include <sys/stat.h> 2062306a36Sopenharmony_ci#include <sys/syscall.h> 2162306a36Sopenharmony_ci#include <dirent.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/err.h> 2462306a36Sopenharmony_ci#include <linux/perf_event.h> 2562306a36Sopenharmony_ci#include <linux/sizes.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <bpf/bpf.h> 2862306a36Sopenharmony_ci#include <bpf/btf.h> 2962306a36Sopenharmony_ci#include <bpf/hashmap.h> 3062306a36Sopenharmony_ci#include <bpf/libbpf.h> 3162306a36Sopenharmony_ci#include <bpf/libbpf_internal.h> 3262306a36Sopenharmony_ci#include <bpf/skel_internal.h> 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#include "cfg.h" 3562306a36Sopenharmony_ci#include "main.h" 3662306a36Sopenharmony_ci#include "xlated_dumper.h" 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define BPF_METADATA_PREFIX "bpf_metadata_" 3962306a36Sopenharmony_ci#define BPF_METADATA_PREFIX_LEN (sizeof(BPF_METADATA_PREFIX) - 1) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cienum dump_mode { 4262306a36Sopenharmony_ci DUMP_JITED, 4362306a36Sopenharmony_ci DUMP_XLATED, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const bool attach_types[] = { 4762306a36Sopenharmony_ci [BPF_SK_SKB_STREAM_PARSER] = true, 4862306a36Sopenharmony_ci [BPF_SK_SKB_STREAM_VERDICT] = true, 4962306a36Sopenharmony_ci [BPF_SK_SKB_VERDICT] = true, 5062306a36Sopenharmony_ci [BPF_SK_MSG_VERDICT] = true, 5162306a36Sopenharmony_ci [BPF_FLOW_DISSECTOR] = true, 5262306a36Sopenharmony_ci [__MAX_BPF_ATTACH_TYPE] = false, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci/* Textual representations traditionally used by the program and kept around 5662306a36Sopenharmony_ci * for the sake of backwards compatibility. 5762306a36Sopenharmony_ci */ 5862306a36Sopenharmony_cistatic const char * const attach_type_strings[] = { 5962306a36Sopenharmony_ci [BPF_SK_SKB_STREAM_PARSER] = "stream_parser", 6062306a36Sopenharmony_ci [BPF_SK_SKB_STREAM_VERDICT] = "stream_verdict", 6162306a36Sopenharmony_ci [BPF_SK_SKB_VERDICT] = "skb_verdict", 6262306a36Sopenharmony_ci [BPF_SK_MSG_VERDICT] = "msg_verdict", 6362306a36Sopenharmony_ci [__MAX_BPF_ATTACH_TYPE] = NULL, 6462306a36Sopenharmony_ci}; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_cistatic struct hashmap *prog_table; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic enum bpf_attach_type parse_attach_type(const char *str) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci enum bpf_attach_type type; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci for (type = 0; type < __MAX_BPF_ATTACH_TYPE; type++) { 7362306a36Sopenharmony_ci if (attach_types[type]) { 7462306a36Sopenharmony_ci const char *attach_type_str; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci attach_type_str = libbpf_bpf_attach_type_str(type); 7762306a36Sopenharmony_ci if (!strcmp(str, attach_type_str)) 7862306a36Sopenharmony_ci return type; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (attach_type_strings[type] && 8262306a36Sopenharmony_ci is_prefix(str, attach_type_strings[type])) 8362306a36Sopenharmony_ci return type; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return __MAX_BPF_ATTACH_TYPE; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic int prep_prog_info(struct bpf_prog_info *const info, enum dump_mode mode, 9062306a36Sopenharmony_ci void **info_data, size_t *const info_data_sz) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct bpf_prog_info holder = {}; 9362306a36Sopenharmony_ci size_t needed = 0; 9462306a36Sopenharmony_ci void *ptr; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci if (mode == DUMP_JITED) { 9762306a36Sopenharmony_ci holder.jited_prog_len = info->jited_prog_len; 9862306a36Sopenharmony_ci needed += info->jited_prog_len; 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci holder.xlated_prog_len = info->xlated_prog_len; 10162306a36Sopenharmony_ci needed += info->xlated_prog_len; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci holder.nr_jited_ksyms = info->nr_jited_ksyms; 10562306a36Sopenharmony_ci needed += info->nr_jited_ksyms * sizeof(__u64); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci holder.nr_jited_func_lens = info->nr_jited_func_lens; 10862306a36Sopenharmony_ci needed += info->nr_jited_func_lens * sizeof(__u32); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci holder.nr_func_info = info->nr_func_info; 11162306a36Sopenharmony_ci holder.func_info_rec_size = info->func_info_rec_size; 11262306a36Sopenharmony_ci needed += info->nr_func_info * info->func_info_rec_size; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci holder.nr_line_info = info->nr_line_info; 11562306a36Sopenharmony_ci holder.line_info_rec_size = info->line_info_rec_size; 11662306a36Sopenharmony_ci needed += info->nr_line_info * info->line_info_rec_size; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci holder.nr_jited_line_info = info->nr_jited_line_info; 11962306a36Sopenharmony_ci holder.jited_line_info_rec_size = info->jited_line_info_rec_size; 12062306a36Sopenharmony_ci needed += info->nr_jited_line_info * info->jited_line_info_rec_size; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci if (needed > *info_data_sz) { 12362306a36Sopenharmony_ci ptr = realloc(*info_data, needed); 12462306a36Sopenharmony_ci if (!ptr) 12562306a36Sopenharmony_ci return -1; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci *info_data = ptr; 12862306a36Sopenharmony_ci *info_data_sz = needed; 12962306a36Sopenharmony_ci } 13062306a36Sopenharmony_ci ptr = *info_data; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci if (mode == DUMP_JITED) { 13362306a36Sopenharmony_ci holder.jited_prog_insns = ptr_to_u64(ptr); 13462306a36Sopenharmony_ci ptr += holder.jited_prog_len; 13562306a36Sopenharmony_ci } else { 13662306a36Sopenharmony_ci holder.xlated_prog_insns = ptr_to_u64(ptr); 13762306a36Sopenharmony_ci ptr += holder.xlated_prog_len; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci holder.jited_ksyms = ptr_to_u64(ptr); 14162306a36Sopenharmony_ci ptr += holder.nr_jited_ksyms * sizeof(__u64); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci holder.jited_func_lens = ptr_to_u64(ptr); 14462306a36Sopenharmony_ci ptr += holder.nr_jited_func_lens * sizeof(__u32); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci holder.func_info = ptr_to_u64(ptr); 14762306a36Sopenharmony_ci ptr += holder.nr_func_info * holder.func_info_rec_size; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci holder.line_info = ptr_to_u64(ptr); 15062306a36Sopenharmony_ci ptr += holder.nr_line_info * holder.line_info_rec_size; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci holder.jited_line_info = ptr_to_u64(ptr); 15362306a36Sopenharmony_ci ptr += holder.nr_jited_line_info * holder.jited_line_info_rec_size; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci *info = holder; 15662306a36Sopenharmony_ci return 0; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic void print_boot_time(__u64 nsecs, char *buf, unsigned int size) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci struct timespec real_time_ts, boot_time_ts; 16262306a36Sopenharmony_ci time_t wallclock_secs; 16362306a36Sopenharmony_ci struct tm load_tm; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci buf[--size] = '\0'; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci if (clock_gettime(CLOCK_REALTIME, &real_time_ts) || 16862306a36Sopenharmony_ci clock_gettime(CLOCK_BOOTTIME, &boot_time_ts)) { 16962306a36Sopenharmony_ci perror("Can't read clocks"); 17062306a36Sopenharmony_ci snprintf(buf, size, "%llu", nsecs / 1000000000); 17162306a36Sopenharmony_ci return; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + 17562306a36Sopenharmony_ci (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / 17662306a36Sopenharmony_ci 1000000000; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if (!localtime_r(&wallclock_secs, &load_tm)) { 18062306a36Sopenharmony_ci snprintf(buf, size, "%llu", nsecs / 1000000000); 18162306a36Sopenharmony_ci return; 18262306a36Sopenharmony_ci } 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci if (json_output) 18562306a36Sopenharmony_ci strftime(buf, size, "%s", &load_tm); 18662306a36Sopenharmony_ci else 18762306a36Sopenharmony_ci strftime(buf, size, "%FT%T%z", &load_tm); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_cistatic void show_prog_maps(int fd, __u32 num_maps) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci struct bpf_prog_info info = {}; 19362306a36Sopenharmony_ci __u32 len = sizeof(info); 19462306a36Sopenharmony_ci __u32 map_ids[num_maps]; 19562306a36Sopenharmony_ci unsigned int i; 19662306a36Sopenharmony_ci int err; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci info.nr_map_ids = num_maps; 19962306a36Sopenharmony_ci info.map_ids = ptr_to_u64(map_ids); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(fd, &info, &len); 20262306a36Sopenharmony_ci if (err || !info.nr_map_ids) 20362306a36Sopenharmony_ci return; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci if (json_output) { 20662306a36Sopenharmony_ci jsonw_name(json_wtr, "map_ids"); 20762306a36Sopenharmony_ci jsonw_start_array(json_wtr); 20862306a36Sopenharmony_ci for (i = 0; i < info.nr_map_ids; i++) 20962306a36Sopenharmony_ci jsonw_uint(json_wtr, map_ids[i]); 21062306a36Sopenharmony_ci jsonw_end_array(json_wtr); 21162306a36Sopenharmony_ci } else { 21262306a36Sopenharmony_ci printf(" map_ids "); 21362306a36Sopenharmony_ci for (i = 0; i < info.nr_map_ids; i++) 21462306a36Sopenharmony_ci printf("%u%s", map_ids[i], 21562306a36Sopenharmony_ci i == info.nr_map_ids - 1 ? "" : ","); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic void *find_metadata(int prog_fd, struct bpf_map_info *map_info) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci struct bpf_prog_info prog_info; 22262306a36Sopenharmony_ci __u32 prog_info_len; 22362306a36Sopenharmony_ci __u32 map_info_len; 22462306a36Sopenharmony_ci void *value = NULL; 22562306a36Sopenharmony_ci __u32 *map_ids; 22662306a36Sopenharmony_ci int nr_maps; 22762306a36Sopenharmony_ci int key = 0; 22862306a36Sopenharmony_ci int map_fd; 22962306a36Sopenharmony_ci int ret; 23062306a36Sopenharmony_ci __u32 i; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci memset(&prog_info, 0, sizeof(prog_info)); 23362306a36Sopenharmony_ci prog_info_len = sizeof(prog_info); 23462306a36Sopenharmony_ci ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 23562306a36Sopenharmony_ci if (ret) 23662306a36Sopenharmony_ci return NULL; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (!prog_info.nr_map_ids) 23962306a36Sopenharmony_ci return NULL; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci map_ids = calloc(prog_info.nr_map_ids, sizeof(__u32)); 24262306a36Sopenharmony_ci if (!map_ids) 24362306a36Sopenharmony_ci return NULL; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci nr_maps = prog_info.nr_map_ids; 24662306a36Sopenharmony_ci memset(&prog_info, 0, sizeof(prog_info)); 24762306a36Sopenharmony_ci prog_info.nr_map_ids = nr_maps; 24862306a36Sopenharmony_ci prog_info.map_ids = ptr_to_u64(map_ids); 24962306a36Sopenharmony_ci prog_info_len = sizeof(prog_info); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci ret = bpf_prog_get_info_by_fd(prog_fd, &prog_info, &prog_info_len); 25262306a36Sopenharmony_ci if (ret) 25362306a36Sopenharmony_ci goto free_map_ids; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci for (i = 0; i < prog_info.nr_map_ids; i++) { 25662306a36Sopenharmony_ci map_fd = bpf_map_get_fd_by_id(map_ids[i]); 25762306a36Sopenharmony_ci if (map_fd < 0) 25862306a36Sopenharmony_ci goto free_map_ids; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci memset(map_info, 0, sizeof(*map_info)); 26162306a36Sopenharmony_ci map_info_len = sizeof(*map_info); 26262306a36Sopenharmony_ci ret = bpf_map_get_info_by_fd(map_fd, map_info, &map_info_len); 26362306a36Sopenharmony_ci if (ret < 0) { 26462306a36Sopenharmony_ci close(map_fd); 26562306a36Sopenharmony_ci goto free_map_ids; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (map_info->type != BPF_MAP_TYPE_ARRAY || 26962306a36Sopenharmony_ci map_info->key_size != sizeof(int) || 27062306a36Sopenharmony_ci map_info->max_entries != 1 || 27162306a36Sopenharmony_ci !map_info->btf_value_type_id || 27262306a36Sopenharmony_ci !strstr(map_info->name, ".rodata")) { 27362306a36Sopenharmony_ci close(map_fd); 27462306a36Sopenharmony_ci continue; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci value = malloc(map_info->value_size); 27862306a36Sopenharmony_ci if (!value) { 27962306a36Sopenharmony_ci close(map_fd); 28062306a36Sopenharmony_ci goto free_map_ids; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (bpf_map_lookup_elem(map_fd, &key, value)) { 28462306a36Sopenharmony_ci close(map_fd); 28562306a36Sopenharmony_ci free(value); 28662306a36Sopenharmony_ci value = NULL; 28762306a36Sopenharmony_ci goto free_map_ids; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci close(map_fd); 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cifree_map_ids: 29562306a36Sopenharmony_ci free(map_ids); 29662306a36Sopenharmony_ci return value; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic bool has_metadata_prefix(const char *s) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci return strncmp(s, BPF_METADATA_PREFIX, BPF_METADATA_PREFIX_LEN) == 0; 30262306a36Sopenharmony_ci} 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_cistatic void show_prog_metadata(int fd, __u32 num_maps) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci const struct btf_type *t_datasec, *t_var; 30762306a36Sopenharmony_ci struct bpf_map_info map_info; 30862306a36Sopenharmony_ci struct btf_var_secinfo *vsi; 30962306a36Sopenharmony_ci bool printed_header = false; 31062306a36Sopenharmony_ci unsigned int i, vlen; 31162306a36Sopenharmony_ci void *value = NULL; 31262306a36Sopenharmony_ci const char *name; 31362306a36Sopenharmony_ci struct btf *btf; 31462306a36Sopenharmony_ci int err; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (!num_maps) 31762306a36Sopenharmony_ci return; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci memset(&map_info, 0, sizeof(map_info)); 32062306a36Sopenharmony_ci value = find_metadata(fd, &map_info); 32162306a36Sopenharmony_ci if (!value) 32262306a36Sopenharmony_ci return; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci btf = btf__load_from_kernel_by_id(map_info.btf_id); 32562306a36Sopenharmony_ci if (!btf) 32662306a36Sopenharmony_ci goto out_free; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci t_datasec = btf__type_by_id(btf, map_info.btf_value_type_id); 32962306a36Sopenharmony_ci if (!btf_is_datasec(t_datasec)) 33062306a36Sopenharmony_ci goto out_free; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci vlen = btf_vlen(t_datasec); 33362306a36Sopenharmony_ci vsi = btf_var_secinfos(t_datasec); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* We don't proceed to check the kinds of the elements of the DATASEC. 33662306a36Sopenharmony_ci * The verifier enforces them to be BTF_KIND_VAR. 33762306a36Sopenharmony_ci */ 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (json_output) { 34062306a36Sopenharmony_ci struct btf_dumper d = { 34162306a36Sopenharmony_ci .btf = btf, 34262306a36Sopenharmony_ci .jw = json_wtr, 34362306a36Sopenharmony_ci .is_plain_text = false, 34462306a36Sopenharmony_ci }; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci for (i = 0; i < vlen; i++, vsi++) { 34762306a36Sopenharmony_ci t_var = btf__type_by_id(btf, vsi->type); 34862306a36Sopenharmony_ci name = btf__name_by_offset(btf, t_var->name_off); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!has_metadata_prefix(name)) 35162306a36Sopenharmony_ci continue; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (!printed_header) { 35462306a36Sopenharmony_ci jsonw_name(json_wtr, "metadata"); 35562306a36Sopenharmony_ci jsonw_start_object(json_wtr); 35662306a36Sopenharmony_ci printed_header = true; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci jsonw_name(json_wtr, name + BPF_METADATA_PREFIX_LEN); 36062306a36Sopenharmony_ci err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 36162306a36Sopenharmony_ci if (err) { 36262306a36Sopenharmony_ci p_err("btf dump failed: %d", err); 36362306a36Sopenharmony_ci break; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci } 36662306a36Sopenharmony_ci if (printed_header) 36762306a36Sopenharmony_ci jsonw_end_object(json_wtr); 36862306a36Sopenharmony_ci } else { 36962306a36Sopenharmony_ci json_writer_t *btf_wtr; 37062306a36Sopenharmony_ci struct btf_dumper d = { 37162306a36Sopenharmony_ci .btf = btf, 37262306a36Sopenharmony_ci .is_plain_text = true, 37362306a36Sopenharmony_ci }; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci for (i = 0; i < vlen; i++, vsi++) { 37662306a36Sopenharmony_ci t_var = btf__type_by_id(btf, vsi->type); 37762306a36Sopenharmony_ci name = btf__name_by_offset(btf, t_var->name_off); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci if (!has_metadata_prefix(name)) 38062306a36Sopenharmony_ci continue; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (!printed_header) { 38362306a36Sopenharmony_ci printf("\tmetadata:"); 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci btf_wtr = jsonw_new(stdout); 38662306a36Sopenharmony_ci if (!btf_wtr) { 38762306a36Sopenharmony_ci p_err("jsonw alloc failed"); 38862306a36Sopenharmony_ci goto out_free; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci d.jw = btf_wtr, 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci printed_header = true; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci printf("\n\t\t%s = ", name + BPF_METADATA_PREFIX_LEN); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci jsonw_reset(btf_wtr); 39862306a36Sopenharmony_ci err = btf_dumper_type(&d, t_var->type, value + vsi->offset); 39962306a36Sopenharmony_ci if (err) { 40062306a36Sopenharmony_ci p_err("btf dump failed: %d", err); 40162306a36Sopenharmony_ci break; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci if (printed_header) 40562306a36Sopenharmony_ci jsonw_destroy(&btf_wtr); 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciout_free: 40962306a36Sopenharmony_ci btf__free(btf); 41062306a36Sopenharmony_ci free(value); 41162306a36Sopenharmony_ci} 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_cistatic void print_prog_header_json(struct bpf_prog_info *info, int fd) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci const char *prog_type_str; 41662306a36Sopenharmony_ci char prog_name[MAX_PROG_FULL_NAME]; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "id", info->id); 41962306a36Sopenharmony_ci prog_type_str = libbpf_bpf_prog_type_str(info->type); 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci if (prog_type_str) 42262306a36Sopenharmony_ci jsonw_string_field(json_wtr, "type", prog_type_str); 42362306a36Sopenharmony_ci else 42462306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "type", info->type); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci if (*info->name) { 42762306a36Sopenharmony_ci get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 42862306a36Sopenharmony_ci jsonw_string_field(json_wtr, "name", prog_name); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci jsonw_name(json_wtr, "tag"); 43262306a36Sopenharmony_ci jsonw_printf(json_wtr, "\"" BPF_TAG_FMT "\"", 43362306a36Sopenharmony_ci info->tag[0], info->tag[1], info->tag[2], info->tag[3], 43462306a36Sopenharmony_ci info->tag[4], info->tag[5], info->tag[6], info->tag[7]); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci jsonw_bool_field(json_wtr, "gpl_compatible", info->gpl_compatible); 43762306a36Sopenharmony_ci if (info->run_time_ns) { 43862306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "run_time_ns", info->run_time_ns); 43962306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "run_cnt", info->run_cnt); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci if (info->recursion_misses) 44262306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "recursion_misses", info->recursion_misses); 44362306a36Sopenharmony_ci} 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_cistatic void print_prog_json(struct bpf_prog_info *info, int fd) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci char *memlock; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci jsonw_start_object(json_wtr); 45062306a36Sopenharmony_ci print_prog_header_json(info, fd); 45162306a36Sopenharmony_ci print_dev_json(info->ifindex, info->netns_dev, info->netns_ino); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci if (info->load_time) { 45462306a36Sopenharmony_ci char buf[32]; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci print_boot_time(info->load_time, buf, sizeof(buf)); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci /* Piggy back on load_time, since 0 uid is a valid one */ 45962306a36Sopenharmony_ci jsonw_name(json_wtr, "loaded_at"); 46062306a36Sopenharmony_ci jsonw_printf(json_wtr, "%s", buf); 46162306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "uid", info->created_by_uid); 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "bytes_xlated", info->xlated_prog_len); 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci if (info->jited_prog_len) { 46762306a36Sopenharmony_ci jsonw_bool_field(json_wtr, "jited", true); 46862306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "bytes_jited", info->jited_prog_len); 46962306a36Sopenharmony_ci } else { 47062306a36Sopenharmony_ci jsonw_bool_field(json_wtr, "jited", false); 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci memlock = get_fdinfo(fd, "memlock"); 47462306a36Sopenharmony_ci if (memlock) 47562306a36Sopenharmony_ci jsonw_int_field(json_wtr, "bytes_memlock", atoll(memlock)); 47662306a36Sopenharmony_ci free(memlock); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (info->nr_map_ids) 47962306a36Sopenharmony_ci show_prog_maps(fd, info->nr_map_ids); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci if (info->btf_id) 48262306a36Sopenharmony_ci jsonw_int_field(json_wtr, "btf_id", info->btf_id); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci if (!hashmap__empty(prog_table)) { 48562306a36Sopenharmony_ci struct hashmap_entry *entry; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci jsonw_name(json_wtr, "pinned"); 48862306a36Sopenharmony_ci jsonw_start_array(json_wtr); 48962306a36Sopenharmony_ci hashmap__for_each_key_entry(prog_table, entry, info->id) 49062306a36Sopenharmony_ci jsonw_string(json_wtr, entry->pvalue); 49162306a36Sopenharmony_ci jsonw_end_array(json_wtr); 49262306a36Sopenharmony_ci } 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci emit_obj_refs_json(refs_table, info->id, json_wtr); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci show_prog_metadata(fd, info->nr_map_ids); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci jsonw_end_object(json_wtr); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void print_prog_header_plain(struct bpf_prog_info *info, int fd) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci const char *prog_type_str; 50462306a36Sopenharmony_ci char prog_name[MAX_PROG_FULL_NAME]; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci printf("%u: ", info->id); 50762306a36Sopenharmony_ci prog_type_str = libbpf_bpf_prog_type_str(info->type); 50862306a36Sopenharmony_ci if (prog_type_str) 50962306a36Sopenharmony_ci printf("%s ", prog_type_str); 51062306a36Sopenharmony_ci else 51162306a36Sopenharmony_ci printf("type %u ", info->type); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (*info->name) { 51462306a36Sopenharmony_ci get_prog_full_name(info, fd, prog_name, sizeof(prog_name)); 51562306a36Sopenharmony_ci printf("name %s ", prog_name); 51662306a36Sopenharmony_ci } 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci printf("tag "); 51962306a36Sopenharmony_ci fprint_hex(stdout, info->tag, BPF_TAG_SIZE, ""); 52062306a36Sopenharmony_ci print_dev_plain(info->ifindex, info->netns_dev, info->netns_ino); 52162306a36Sopenharmony_ci printf("%s", info->gpl_compatible ? " gpl" : ""); 52262306a36Sopenharmony_ci if (info->run_time_ns) 52362306a36Sopenharmony_ci printf(" run_time_ns %lld run_cnt %lld", 52462306a36Sopenharmony_ci info->run_time_ns, info->run_cnt); 52562306a36Sopenharmony_ci if (info->recursion_misses) 52662306a36Sopenharmony_ci printf(" recursion_misses %lld", info->recursion_misses); 52762306a36Sopenharmony_ci printf("\n"); 52862306a36Sopenharmony_ci} 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_cistatic void print_prog_plain(struct bpf_prog_info *info, int fd) 53162306a36Sopenharmony_ci{ 53262306a36Sopenharmony_ci char *memlock; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci print_prog_header_plain(info, fd); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci if (info->load_time) { 53762306a36Sopenharmony_ci char buf[32]; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci print_boot_time(info->load_time, buf, sizeof(buf)); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* Piggy back on load_time, since 0 uid is a valid one */ 54262306a36Sopenharmony_ci printf("\tloaded_at %s uid %u\n", buf, info->created_by_uid); 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci printf("\txlated %uB", info->xlated_prog_len); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci if (info->jited_prog_len) 54862306a36Sopenharmony_ci printf(" jited %uB", info->jited_prog_len); 54962306a36Sopenharmony_ci else 55062306a36Sopenharmony_ci printf(" not jited"); 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci memlock = get_fdinfo(fd, "memlock"); 55362306a36Sopenharmony_ci if (memlock) 55462306a36Sopenharmony_ci printf(" memlock %sB", memlock); 55562306a36Sopenharmony_ci free(memlock); 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (info->nr_map_ids) 55862306a36Sopenharmony_ci show_prog_maps(fd, info->nr_map_ids); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (!hashmap__empty(prog_table)) { 56162306a36Sopenharmony_ci struct hashmap_entry *entry; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci hashmap__for_each_key_entry(prog_table, entry, info->id) 56462306a36Sopenharmony_ci printf("\n\tpinned %s", (char *)entry->pvalue); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (info->btf_id) 56862306a36Sopenharmony_ci printf("\n\tbtf_id %d", info->btf_id); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci emit_obj_refs_plain(refs_table, info->id, "\n\tpids "); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci printf("\n"); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci show_prog_metadata(fd, info->nr_map_ids); 57562306a36Sopenharmony_ci} 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_cistatic int show_prog(int fd) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct bpf_prog_info info = {}; 58062306a36Sopenharmony_ci __u32 len = sizeof(info); 58162306a36Sopenharmony_ci int err; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(fd, &info, &len); 58462306a36Sopenharmony_ci if (err) { 58562306a36Sopenharmony_ci p_err("can't get prog info: %s", strerror(errno)); 58662306a36Sopenharmony_ci return -1; 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (json_output) 59062306a36Sopenharmony_ci print_prog_json(&info, fd); 59162306a36Sopenharmony_ci else 59262306a36Sopenharmony_ci print_prog_plain(&info, fd); 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci return 0; 59562306a36Sopenharmony_ci} 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_cistatic int do_show_subset(int argc, char **argv) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci int *fds = NULL; 60062306a36Sopenharmony_ci int nb_fds, i; 60162306a36Sopenharmony_ci int err = -1; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci fds = malloc(sizeof(int)); 60462306a36Sopenharmony_ci if (!fds) { 60562306a36Sopenharmony_ci p_err("mem alloc failed"); 60662306a36Sopenharmony_ci return -1; 60762306a36Sopenharmony_ci } 60862306a36Sopenharmony_ci nb_fds = prog_parse_fds(&argc, &argv, &fds); 60962306a36Sopenharmony_ci if (nb_fds < 1) 61062306a36Sopenharmony_ci goto exit_free; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (json_output && nb_fds > 1) 61362306a36Sopenharmony_ci jsonw_start_array(json_wtr); /* root array */ 61462306a36Sopenharmony_ci for (i = 0; i < nb_fds; i++) { 61562306a36Sopenharmony_ci err = show_prog(fds[i]); 61662306a36Sopenharmony_ci if (err) { 61762306a36Sopenharmony_ci for (; i < nb_fds; i++) 61862306a36Sopenharmony_ci close(fds[i]); 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci close(fds[i]); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci if (json_output && nb_fds > 1) 62462306a36Sopenharmony_ci jsonw_end_array(json_wtr); /* root array */ 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ciexit_free: 62762306a36Sopenharmony_ci free(fds); 62862306a36Sopenharmony_ci return err; 62962306a36Sopenharmony_ci} 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_cistatic int do_show(int argc, char **argv) 63262306a36Sopenharmony_ci{ 63362306a36Sopenharmony_ci __u32 id = 0; 63462306a36Sopenharmony_ci int err; 63562306a36Sopenharmony_ci int fd; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci if (show_pinned) { 63862306a36Sopenharmony_ci prog_table = hashmap__new(hash_fn_for_key_as_id, 63962306a36Sopenharmony_ci equal_fn_for_key_as_id, NULL); 64062306a36Sopenharmony_ci if (IS_ERR(prog_table)) { 64162306a36Sopenharmony_ci p_err("failed to create hashmap for pinned paths"); 64262306a36Sopenharmony_ci return -1; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci build_pinned_obj_table(prog_table, BPF_OBJ_PROG); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci build_obj_refs_table(&refs_table, BPF_OBJ_PROG); 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci if (argc == 2) 64962306a36Sopenharmony_ci return do_show_subset(argc, argv); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (argc) 65262306a36Sopenharmony_ci return BAD_ARG(); 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (json_output) 65562306a36Sopenharmony_ci jsonw_start_array(json_wtr); 65662306a36Sopenharmony_ci while (true) { 65762306a36Sopenharmony_ci err = bpf_prog_get_next_id(id, &id); 65862306a36Sopenharmony_ci if (err) { 65962306a36Sopenharmony_ci if (errno == ENOENT) { 66062306a36Sopenharmony_ci err = 0; 66162306a36Sopenharmony_ci break; 66262306a36Sopenharmony_ci } 66362306a36Sopenharmony_ci p_err("can't get next program: %s%s", strerror(errno), 66462306a36Sopenharmony_ci errno == EINVAL ? " -- kernel too old?" : ""); 66562306a36Sopenharmony_ci err = -1; 66662306a36Sopenharmony_ci break; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci fd = bpf_prog_get_fd_by_id(id); 67062306a36Sopenharmony_ci if (fd < 0) { 67162306a36Sopenharmony_ci if (errno == ENOENT) 67262306a36Sopenharmony_ci continue; 67362306a36Sopenharmony_ci p_err("can't get prog by id (%u): %s", 67462306a36Sopenharmony_ci id, strerror(errno)); 67562306a36Sopenharmony_ci err = -1; 67662306a36Sopenharmony_ci break; 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci err = show_prog(fd); 68062306a36Sopenharmony_ci close(fd); 68162306a36Sopenharmony_ci if (err) 68262306a36Sopenharmony_ci break; 68362306a36Sopenharmony_ci } 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci if (json_output) 68662306a36Sopenharmony_ci jsonw_end_array(json_wtr); 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci delete_obj_refs_table(refs_table); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (show_pinned) 69162306a36Sopenharmony_ci delete_pinned_obj_table(prog_table); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return err; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic int 69762306a36Sopenharmony_ciprog_dump(struct bpf_prog_info *info, enum dump_mode mode, 69862306a36Sopenharmony_ci char *filepath, bool opcodes, bool visual, bool linum) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct bpf_prog_linfo *prog_linfo = NULL; 70162306a36Sopenharmony_ci const char *disasm_opt = NULL; 70262306a36Sopenharmony_ci struct dump_data dd = {}; 70362306a36Sopenharmony_ci void *func_info = NULL; 70462306a36Sopenharmony_ci struct btf *btf = NULL; 70562306a36Sopenharmony_ci char func_sig[1024]; 70662306a36Sopenharmony_ci unsigned char *buf; 70762306a36Sopenharmony_ci __u32 member_len; 70862306a36Sopenharmony_ci int fd, err = -1; 70962306a36Sopenharmony_ci ssize_t n; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci if (mode == DUMP_JITED) { 71262306a36Sopenharmony_ci if (info->jited_prog_len == 0 || !info->jited_prog_insns) { 71362306a36Sopenharmony_ci p_info("no instructions returned"); 71462306a36Sopenharmony_ci return -1; 71562306a36Sopenharmony_ci } 71662306a36Sopenharmony_ci buf = u64_to_ptr(info->jited_prog_insns); 71762306a36Sopenharmony_ci member_len = info->jited_prog_len; 71862306a36Sopenharmony_ci } else { /* DUMP_XLATED */ 71962306a36Sopenharmony_ci if (info->xlated_prog_len == 0 || !info->xlated_prog_insns) { 72062306a36Sopenharmony_ci p_err("error retrieving insn dump: kernel.kptr_restrict set?"); 72162306a36Sopenharmony_ci return -1; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci buf = u64_to_ptr(info->xlated_prog_insns); 72462306a36Sopenharmony_ci member_len = info->xlated_prog_len; 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (info->btf_id) { 72862306a36Sopenharmony_ci btf = btf__load_from_kernel_by_id(info->btf_id); 72962306a36Sopenharmony_ci if (!btf) { 73062306a36Sopenharmony_ci p_err("failed to get btf"); 73162306a36Sopenharmony_ci return -1; 73262306a36Sopenharmony_ci } 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci func_info = u64_to_ptr(info->func_info); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci if (info->nr_line_info) { 73862306a36Sopenharmony_ci prog_linfo = bpf_prog_linfo__new(info); 73962306a36Sopenharmony_ci if (!prog_linfo) 74062306a36Sopenharmony_ci p_info("error in processing bpf_line_info. continue without it."); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (filepath) { 74462306a36Sopenharmony_ci fd = open(filepath, O_WRONLY | O_CREAT | O_TRUNC, 0600); 74562306a36Sopenharmony_ci if (fd < 0) { 74662306a36Sopenharmony_ci p_err("can't open file %s: %s", filepath, 74762306a36Sopenharmony_ci strerror(errno)); 74862306a36Sopenharmony_ci goto exit_free; 74962306a36Sopenharmony_ci } 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci n = write(fd, buf, member_len); 75262306a36Sopenharmony_ci close(fd); 75362306a36Sopenharmony_ci if (n != (ssize_t)member_len) { 75462306a36Sopenharmony_ci p_err("error writing output file: %s", 75562306a36Sopenharmony_ci n < 0 ? strerror(errno) : "short write"); 75662306a36Sopenharmony_ci goto exit_free; 75762306a36Sopenharmony_ci } 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (json_output) 76062306a36Sopenharmony_ci jsonw_null(json_wtr); 76162306a36Sopenharmony_ci } else if (mode == DUMP_JITED) { 76262306a36Sopenharmony_ci const char *name = NULL; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (info->ifindex) { 76562306a36Sopenharmony_ci name = ifindex_to_arch(info->ifindex, info->netns_dev, 76662306a36Sopenharmony_ci info->netns_ino, &disasm_opt); 76762306a36Sopenharmony_ci if (!name) 76862306a36Sopenharmony_ci goto exit_free; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci if (info->nr_jited_func_lens && info->jited_func_lens) { 77262306a36Sopenharmony_ci struct kernel_sym *sym = NULL; 77362306a36Sopenharmony_ci struct bpf_func_info *record; 77462306a36Sopenharmony_ci char sym_name[SYM_MAX_NAME]; 77562306a36Sopenharmony_ci unsigned char *img = buf; 77662306a36Sopenharmony_ci __u64 *ksyms = NULL; 77762306a36Sopenharmony_ci __u32 *lens; 77862306a36Sopenharmony_ci __u32 i; 77962306a36Sopenharmony_ci if (info->nr_jited_ksyms) { 78062306a36Sopenharmony_ci kernel_syms_load(&dd); 78162306a36Sopenharmony_ci ksyms = u64_to_ptr(info->jited_ksyms); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (json_output) 78562306a36Sopenharmony_ci jsonw_start_array(json_wtr); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci lens = u64_to_ptr(info->jited_func_lens); 78862306a36Sopenharmony_ci for (i = 0; i < info->nr_jited_func_lens; i++) { 78962306a36Sopenharmony_ci if (ksyms) { 79062306a36Sopenharmony_ci sym = kernel_syms_search(&dd, ksyms[i]); 79162306a36Sopenharmony_ci if (sym) 79262306a36Sopenharmony_ci sprintf(sym_name, "%s", sym->name); 79362306a36Sopenharmony_ci else 79462306a36Sopenharmony_ci sprintf(sym_name, "0x%016llx", ksyms[i]); 79562306a36Sopenharmony_ci } else { 79662306a36Sopenharmony_ci strcpy(sym_name, "unknown"); 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci if (func_info) { 80062306a36Sopenharmony_ci record = func_info + i * info->func_info_rec_size; 80162306a36Sopenharmony_ci btf_dumper_type_only(btf, record->type_id, 80262306a36Sopenharmony_ci func_sig, 80362306a36Sopenharmony_ci sizeof(func_sig)); 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (json_output) { 80762306a36Sopenharmony_ci jsonw_start_object(json_wtr); 80862306a36Sopenharmony_ci if (func_info && func_sig[0] != '\0') { 80962306a36Sopenharmony_ci jsonw_name(json_wtr, "proto"); 81062306a36Sopenharmony_ci jsonw_string(json_wtr, func_sig); 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci jsonw_name(json_wtr, "name"); 81362306a36Sopenharmony_ci jsonw_string(json_wtr, sym_name); 81462306a36Sopenharmony_ci jsonw_name(json_wtr, "insns"); 81562306a36Sopenharmony_ci } else { 81662306a36Sopenharmony_ci if (func_info && func_sig[0] != '\0') 81762306a36Sopenharmony_ci printf("%s:\n", func_sig); 81862306a36Sopenharmony_ci printf("%s:\n", sym_name); 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (disasm_print_insn(img, lens[i], opcodes, 82262306a36Sopenharmony_ci name, disasm_opt, btf, 82362306a36Sopenharmony_ci prog_linfo, ksyms[i], i, 82462306a36Sopenharmony_ci linum)) 82562306a36Sopenharmony_ci goto exit_free; 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci img += lens[i]; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci if (json_output) 83062306a36Sopenharmony_ci jsonw_end_object(json_wtr); 83162306a36Sopenharmony_ci else 83262306a36Sopenharmony_ci printf("\n"); 83362306a36Sopenharmony_ci } 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci if (json_output) 83662306a36Sopenharmony_ci jsonw_end_array(json_wtr); 83762306a36Sopenharmony_ci } else { 83862306a36Sopenharmony_ci if (disasm_print_insn(buf, member_len, opcodes, name, 83962306a36Sopenharmony_ci disasm_opt, btf, NULL, 0, 0, 84062306a36Sopenharmony_ci false)) 84162306a36Sopenharmony_ci goto exit_free; 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } else { 84462306a36Sopenharmony_ci kernel_syms_load(&dd); 84562306a36Sopenharmony_ci dd.nr_jited_ksyms = info->nr_jited_ksyms; 84662306a36Sopenharmony_ci dd.jited_ksyms = u64_to_ptr(info->jited_ksyms); 84762306a36Sopenharmony_ci dd.btf = btf; 84862306a36Sopenharmony_ci dd.func_info = func_info; 84962306a36Sopenharmony_ci dd.finfo_rec_size = info->func_info_rec_size; 85062306a36Sopenharmony_ci dd.prog_linfo = prog_linfo; 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci if (json_output) 85362306a36Sopenharmony_ci dump_xlated_json(&dd, buf, member_len, opcodes, linum); 85462306a36Sopenharmony_ci else if (visual) 85562306a36Sopenharmony_ci dump_xlated_cfg(&dd, buf, member_len, opcodes, linum); 85662306a36Sopenharmony_ci else 85762306a36Sopenharmony_ci dump_xlated_plain(&dd, buf, member_len, opcodes, linum); 85862306a36Sopenharmony_ci kernel_syms_destroy(&dd); 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci err = 0; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ciexit_free: 86462306a36Sopenharmony_ci btf__free(btf); 86562306a36Sopenharmony_ci bpf_prog_linfo__free(prog_linfo); 86662306a36Sopenharmony_ci return err; 86762306a36Sopenharmony_ci} 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_cistatic int do_dump(int argc, char **argv) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct bpf_prog_info info; 87262306a36Sopenharmony_ci __u32 info_len = sizeof(info); 87362306a36Sopenharmony_ci size_t info_data_sz = 0; 87462306a36Sopenharmony_ci void *info_data = NULL; 87562306a36Sopenharmony_ci char *filepath = NULL; 87662306a36Sopenharmony_ci bool opcodes = false; 87762306a36Sopenharmony_ci bool visual = false; 87862306a36Sopenharmony_ci enum dump_mode mode; 87962306a36Sopenharmony_ci bool linum = false; 88062306a36Sopenharmony_ci int nb_fds, i = 0; 88162306a36Sopenharmony_ci int *fds = NULL; 88262306a36Sopenharmony_ci int err = -1; 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_ci if (is_prefix(*argv, "jited")) { 88562306a36Sopenharmony_ci if (disasm_init()) 88662306a36Sopenharmony_ci return -1; 88762306a36Sopenharmony_ci mode = DUMP_JITED; 88862306a36Sopenharmony_ci } else if (is_prefix(*argv, "xlated")) { 88962306a36Sopenharmony_ci mode = DUMP_XLATED; 89062306a36Sopenharmony_ci } else { 89162306a36Sopenharmony_ci p_err("expected 'xlated' or 'jited', got: %s", *argv); 89262306a36Sopenharmony_ci return -1; 89362306a36Sopenharmony_ci } 89462306a36Sopenharmony_ci NEXT_ARG(); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci if (argc < 2) 89762306a36Sopenharmony_ci usage(); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci fds = malloc(sizeof(int)); 90062306a36Sopenharmony_ci if (!fds) { 90162306a36Sopenharmony_ci p_err("mem alloc failed"); 90262306a36Sopenharmony_ci return -1; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci nb_fds = prog_parse_fds(&argc, &argv, &fds); 90562306a36Sopenharmony_ci if (nb_fds < 1) 90662306a36Sopenharmony_ci goto exit_free; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci while (argc) { 90962306a36Sopenharmony_ci if (is_prefix(*argv, "file")) { 91062306a36Sopenharmony_ci NEXT_ARG(); 91162306a36Sopenharmony_ci if (!argc) { 91262306a36Sopenharmony_ci p_err("expected file path"); 91362306a36Sopenharmony_ci goto exit_close; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci if (nb_fds > 1) { 91662306a36Sopenharmony_ci p_err("several programs matched"); 91762306a36Sopenharmony_ci goto exit_close; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci filepath = *argv; 92162306a36Sopenharmony_ci NEXT_ARG(); 92262306a36Sopenharmony_ci } else if (is_prefix(*argv, "opcodes")) { 92362306a36Sopenharmony_ci opcodes = true; 92462306a36Sopenharmony_ci NEXT_ARG(); 92562306a36Sopenharmony_ci } else if (is_prefix(*argv, "visual")) { 92662306a36Sopenharmony_ci if (nb_fds > 1) { 92762306a36Sopenharmony_ci p_err("several programs matched"); 92862306a36Sopenharmony_ci goto exit_close; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci visual = true; 93262306a36Sopenharmony_ci NEXT_ARG(); 93362306a36Sopenharmony_ci } else if (is_prefix(*argv, "linum")) { 93462306a36Sopenharmony_ci linum = true; 93562306a36Sopenharmony_ci NEXT_ARG(); 93662306a36Sopenharmony_ci } else { 93762306a36Sopenharmony_ci usage(); 93862306a36Sopenharmony_ci goto exit_close; 93962306a36Sopenharmony_ci } 94062306a36Sopenharmony_ci } 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (filepath && (opcodes || visual || linum)) { 94362306a36Sopenharmony_ci p_err("'file' is not compatible with 'opcodes', 'visual', or 'linum'"); 94462306a36Sopenharmony_ci goto exit_close; 94562306a36Sopenharmony_ci } 94662306a36Sopenharmony_ci if (json_output && visual) { 94762306a36Sopenharmony_ci p_err("'visual' is not compatible with JSON output"); 94862306a36Sopenharmony_ci goto exit_close; 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci if (json_output && nb_fds > 1) 95262306a36Sopenharmony_ci jsonw_start_array(json_wtr); /* root array */ 95362306a36Sopenharmony_ci for (i = 0; i < nb_fds; i++) { 95462306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len); 95762306a36Sopenharmony_ci if (err) { 95862306a36Sopenharmony_ci p_err("can't get prog info: %s", strerror(errno)); 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci err = prep_prog_info(&info, mode, &info_data, &info_data_sz); 96362306a36Sopenharmony_ci if (err) { 96462306a36Sopenharmony_ci p_err("can't grow prog info_data"); 96562306a36Sopenharmony_ci break; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(fds[i], &info, &info_len); 96962306a36Sopenharmony_ci if (err) { 97062306a36Sopenharmony_ci p_err("can't get prog info: %s", strerror(errno)); 97162306a36Sopenharmony_ci break; 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (json_output && nb_fds > 1) { 97562306a36Sopenharmony_ci jsonw_start_object(json_wtr); /* prog object */ 97662306a36Sopenharmony_ci print_prog_header_json(&info, fds[i]); 97762306a36Sopenharmony_ci jsonw_name(json_wtr, "insns"); 97862306a36Sopenharmony_ci } else if (nb_fds > 1) { 97962306a36Sopenharmony_ci print_prog_header_plain(&info, fds[i]); 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci err = prog_dump(&info, mode, filepath, opcodes, visual, linum); 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (json_output && nb_fds > 1) 98562306a36Sopenharmony_ci jsonw_end_object(json_wtr); /* prog object */ 98662306a36Sopenharmony_ci else if (i != nb_fds - 1 && nb_fds > 1) 98762306a36Sopenharmony_ci printf("\n"); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (err) 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci close(fds[i]); 99262306a36Sopenharmony_ci } 99362306a36Sopenharmony_ci if (json_output && nb_fds > 1) 99462306a36Sopenharmony_ci jsonw_end_array(json_wtr); /* root array */ 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ciexit_close: 99762306a36Sopenharmony_ci for (; i < nb_fds; i++) 99862306a36Sopenharmony_ci close(fds[i]); 99962306a36Sopenharmony_ciexit_free: 100062306a36Sopenharmony_ci free(info_data); 100162306a36Sopenharmony_ci free(fds); 100262306a36Sopenharmony_ci return err; 100362306a36Sopenharmony_ci} 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_cistatic int do_pin(int argc, char **argv) 100662306a36Sopenharmony_ci{ 100762306a36Sopenharmony_ci int err; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci err = do_pin_any(argc, argv, prog_parse_fd); 101062306a36Sopenharmony_ci if (!err && json_output) 101162306a36Sopenharmony_ci jsonw_null(json_wtr); 101262306a36Sopenharmony_ci return err; 101362306a36Sopenharmony_ci} 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistruct map_replace { 101662306a36Sopenharmony_ci int idx; 101762306a36Sopenharmony_ci int fd; 101862306a36Sopenharmony_ci char *name; 101962306a36Sopenharmony_ci}; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_cistatic int map_replace_compar(const void *p1, const void *p2) 102262306a36Sopenharmony_ci{ 102362306a36Sopenharmony_ci const struct map_replace *a = p1, *b = p2; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci return a->idx - b->idx; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic int parse_attach_detach_args(int argc, char **argv, int *progfd, 102962306a36Sopenharmony_ci enum bpf_attach_type *attach_type, 103062306a36Sopenharmony_ci int *mapfd) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci if (!REQ_ARGS(3)) 103362306a36Sopenharmony_ci return -EINVAL; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci *progfd = prog_parse_fd(&argc, &argv); 103662306a36Sopenharmony_ci if (*progfd < 0) 103762306a36Sopenharmony_ci return *progfd; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci *attach_type = parse_attach_type(*argv); 104062306a36Sopenharmony_ci if (*attach_type == __MAX_BPF_ATTACH_TYPE) { 104162306a36Sopenharmony_ci p_err("invalid attach/detach type"); 104262306a36Sopenharmony_ci return -EINVAL; 104362306a36Sopenharmony_ci } 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci if (*attach_type == BPF_FLOW_DISSECTOR) { 104662306a36Sopenharmony_ci *mapfd = 0; 104762306a36Sopenharmony_ci return 0; 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci NEXT_ARG(); 105162306a36Sopenharmony_ci if (!REQ_ARGS(2)) 105262306a36Sopenharmony_ci return -EINVAL; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci *mapfd = map_parse_fd(&argc, &argv); 105562306a36Sopenharmony_ci if (*mapfd < 0) 105662306a36Sopenharmony_ci return *mapfd; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci return 0; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic int do_attach(int argc, char **argv) 106262306a36Sopenharmony_ci{ 106362306a36Sopenharmony_ci enum bpf_attach_type attach_type; 106462306a36Sopenharmony_ci int err, progfd; 106562306a36Sopenharmony_ci int mapfd; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci err = parse_attach_detach_args(argc, argv, 106862306a36Sopenharmony_ci &progfd, &attach_type, &mapfd); 106962306a36Sopenharmony_ci if (err) 107062306a36Sopenharmony_ci return err; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci err = bpf_prog_attach(progfd, mapfd, attach_type, 0); 107362306a36Sopenharmony_ci if (err) { 107462306a36Sopenharmony_ci p_err("failed prog attach to map"); 107562306a36Sopenharmony_ci return -EINVAL; 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if (json_output) 107962306a36Sopenharmony_ci jsonw_null(json_wtr); 108062306a36Sopenharmony_ci return 0; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_cistatic int do_detach(int argc, char **argv) 108462306a36Sopenharmony_ci{ 108562306a36Sopenharmony_ci enum bpf_attach_type attach_type; 108662306a36Sopenharmony_ci int err, progfd; 108762306a36Sopenharmony_ci int mapfd; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci err = parse_attach_detach_args(argc, argv, 109062306a36Sopenharmony_ci &progfd, &attach_type, &mapfd); 109162306a36Sopenharmony_ci if (err) 109262306a36Sopenharmony_ci return err; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci err = bpf_prog_detach2(progfd, mapfd, attach_type); 109562306a36Sopenharmony_ci if (err) { 109662306a36Sopenharmony_ci p_err("failed prog detach from map"); 109762306a36Sopenharmony_ci return -EINVAL; 109862306a36Sopenharmony_ci } 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci if (json_output) 110162306a36Sopenharmony_ci jsonw_null(json_wtr); 110262306a36Sopenharmony_ci return 0; 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic int check_single_stdin(char *file_data_in, char *file_ctx_in) 110662306a36Sopenharmony_ci{ 110762306a36Sopenharmony_ci if (file_data_in && file_ctx_in && 110862306a36Sopenharmony_ci !strcmp(file_data_in, "-") && !strcmp(file_ctx_in, "-")) { 110962306a36Sopenharmony_ci p_err("cannot use standard input for both data_in and ctx_in"); 111062306a36Sopenharmony_ci return -1; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int get_run_data(const char *fname, void **data_ptr, unsigned int *size) 111762306a36Sopenharmony_ci{ 111862306a36Sopenharmony_ci size_t block_size = 256; 111962306a36Sopenharmony_ci size_t buf_size = block_size; 112062306a36Sopenharmony_ci size_t nb_read = 0; 112162306a36Sopenharmony_ci void *tmp; 112262306a36Sopenharmony_ci FILE *f; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (!fname) { 112562306a36Sopenharmony_ci *data_ptr = NULL; 112662306a36Sopenharmony_ci *size = 0; 112762306a36Sopenharmony_ci return 0; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci if (!strcmp(fname, "-")) 113162306a36Sopenharmony_ci f = stdin; 113262306a36Sopenharmony_ci else 113362306a36Sopenharmony_ci f = fopen(fname, "r"); 113462306a36Sopenharmony_ci if (!f) { 113562306a36Sopenharmony_ci p_err("failed to open %s: %s", fname, strerror(errno)); 113662306a36Sopenharmony_ci return -1; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci *data_ptr = malloc(block_size); 114062306a36Sopenharmony_ci if (!*data_ptr) { 114162306a36Sopenharmony_ci p_err("failed to allocate memory for data_in/ctx_in: %s", 114262306a36Sopenharmony_ci strerror(errno)); 114362306a36Sopenharmony_ci goto err_fclose; 114462306a36Sopenharmony_ci } 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci while ((nb_read += fread(*data_ptr + nb_read, 1, block_size, f))) { 114762306a36Sopenharmony_ci if (feof(f)) 114862306a36Sopenharmony_ci break; 114962306a36Sopenharmony_ci if (ferror(f)) { 115062306a36Sopenharmony_ci p_err("failed to read data_in/ctx_in from %s: %s", 115162306a36Sopenharmony_ci fname, strerror(errno)); 115262306a36Sopenharmony_ci goto err_free; 115362306a36Sopenharmony_ci } 115462306a36Sopenharmony_ci if (nb_read > buf_size - block_size) { 115562306a36Sopenharmony_ci if (buf_size == UINT32_MAX) { 115662306a36Sopenharmony_ci p_err("data_in/ctx_in is too long (max: %d)", 115762306a36Sopenharmony_ci UINT32_MAX); 115862306a36Sopenharmony_ci goto err_free; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci /* No space for fread()-ing next chunk; realloc() */ 116162306a36Sopenharmony_ci buf_size *= 2; 116262306a36Sopenharmony_ci tmp = realloc(*data_ptr, buf_size); 116362306a36Sopenharmony_ci if (!tmp) { 116462306a36Sopenharmony_ci p_err("failed to reallocate data_in/ctx_in: %s", 116562306a36Sopenharmony_ci strerror(errno)); 116662306a36Sopenharmony_ci goto err_free; 116762306a36Sopenharmony_ci } 116862306a36Sopenharmony_ci *data_ptr = tmp; 116962306a36Sopenharmony_ci } 117062306a36Sopenharmony_ci } 117162306a36Sopenharmony_ci if (f != stdin) 117262306a36Sopenharmony_ci fclose(f); 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci *size = nb_read; 117562306a36Sopenharmony_ci return 0; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_cierr_free: 117862306a36Sopenharmony_ci free(*data_ptr); 117962306a36Sopenharmony_ci *data_ptr = NULL; 118062306a36Sopenharmony_cierr_fclose: 118162306a36Sopenharmony_ci if (f != stdin) 118262306a36Sopenharmony_ci fclose(f); 118362306a36Sopenharmony_ci return -1; 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic void hex_print(void *data, unsigned int size, FILE *f) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci size_t i, j; 118962306a36Sopenharmony_ci char c; 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci for (i = 0; i < size; i += 16) { 119262306a36Sopenharmony_ci /* Row offset */ 119362306a36Sopenharmony_ci fprintf(f, "%07zx\t", i); 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci /* Hexadecimal values */ 119662306a36Sopenharmony_ci for (j = i; j < i + 16 && j < size; j++) 119762306a36Sopenharmony_ci fprintf(f, "%02x%s", *(uint8_t *)(data + j), 119862306a36Sopenharmony_ci j % 2 ? " " : ""); 119962306a36Sopenharmony_ci for (; j < i + 16; j++) 120062306a36Sopenharmony_ci fprintf(f, " %s", j % 2 ? " " : ""); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci /* ASCII values (if relevant), '.' otherwise */ 120362306a36Sopenharmony_ci fprintf(f, "| "); 120462306a36Sopenharmony_ci for (j = i; j < i + 16 && j < size; j++) { 120562306a36Sopenharmony_ci c = *(char *)(data + j); 120662306a36Sopenharmony_ci if (c < ' ' || c > '~') 120762306a36Sopenharmony_ci c = '.'; 120862306a36Sopenharmony_ci fprintf(f, "%c%s", c, j == i + 7 ? " " : ""); 120962306a36Sopenharmony_ci } 121062306a36Sopenharmony_ci 121162306a36Sopenharmony_ci fprintf(f, "\n"); 121262306a36Sopenharmony_ci } 121362306a36Sopenharmony_ci} 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_cistatic int 121662306a36Sopenharmony_ciprint_run_output(void *data, unsigned int size, const char *fname, 121762306a36Sopenharmony_ci const char *json_key) 121862306a36Sopenharmony_ci{ 121962306a36Sopenharmony_ci size_t nb_written; 122062306a36Sopenharmony_ci FILE *f; 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci if (!fname) 122362306a36Sopenharmony_ci return 0; 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_ci if (!strcmp(fname, "-")) { 122662306a36Sopenharmony_ci f = stdout; 122762306a36Sopenharmony_ci if (json_output) { 122862306a36Sopenharmony_ci jsonw_name(json_wtr, json_key); 122962306a36Sopenharmony_ci print_data_json(data, size); 123062306a36Sopenharmony_ci } else { 123162306a36Sopenharmony_ci hex_print(data, size, f); 123262306a36Sopenharmony_ci } 123362306a36Sopenharmony_ci return 0; 123462306a36Sopenharmony_ci } 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_ci f = fopen(fname, "w"); 123762306a36Sopenharmony_ci if (!f) { 123862306a36Sopenharmony_ci p_err("failed to open %s: %s", fname, strerror(errno)); 123962306a36Sopenharmony_ci return -1; 124062306a36Sopenharmony_ci } 124162306a36Sopenharmony_ci 124262306a36Sopenharmony_ci nb_written = fwrite(data, 1, size, f); 124362306a36Sopenharmony_ci fclose(f); 124462306a36Sopenharmony_ci if (nb_written != size) { 124562306a36Sopenharmony_ci p_err("failed to write output data/ctx: %s", strerror(errno)); 124662306a36Sopenharmony_ci return -1; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic int alloc_run_data(void **data_ptr, unsigned int size_out) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci *data_ptr = calloc(size_out, 1); 125562306a36Sopenharmony_ci if (!*data_ptr) { 125662306a36Sopenharmony_ci p_err("failed to allocate memory for output data/ctx: %s", 125762306a36Sopenharmony_ci strerror(errno)); 125862306a36Sopenharmony_ci return -1; 125962306a36Sopenharmony_ci } 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci return 0; 126262306a36Sopenharmony_ci} 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_cistatic int do_run(int argc, char **argv) 126562306a36Sopenharmony_ci{ 126662306a36Sopenharmony_ci char *data_fname_in = NULL, *data_fname_out = NULL; 126762306a36Sopenharmony_ci char *ctx_fname_in = NULL, *ctx_fname_out = NULL; 126862306a36Sopenharmony_ci const unsigned int default_size = SZ_32K; 126962306a36Sopenharmony_ci void *data_in = NULL, *data_out = NULL; 127062306a36Sopenharmony_ci void *ctx_in = NULL, *ctx_out = NULL; 127162306a36Sopenharmony_ci unsigned int repeat = 1; 127262306a36Sopenharmony_ci int fd, err; 127362306a36Sopenharmony_ci LIBBPF_OPTS(bpf_test_run_opts, test_attr); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci if (!REQ_ARGS(4)) 127662306a36Sopenharmony_ci return -1; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci fd = prog_parse_fd(&argc, &argv); 127962306a36Sopenharmony_ci if (fd < 0) 128062306a36Sopenharmony_ci return -1; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci while (argc) { 128362306a36Sopenharmony_ci if (detect_common_prefix(*argv, "data_in", "data_out", 128462306a36Sopenharmony_ci "data_size_out", NULL)) 128562306a36Sopenharmony_ci return -1; 128662306a36Sopenharmony_ci if (detect_common_prefix(*argv, "ctx_in", "ctx_out", 128762306a36Sopenharmony_ci "ctx_size_out", NULL)) 128862306a36Sopenharmony_ci return -1; 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (is_prefix(*argv, "data_in")) { 129162306a36Sopenharmony_ci NEXT_ARG(); 129262306a36Sopenharmony_ci if (!REQ_ARGS(1)) 129362306a36Sopenharmony_ci return -1; 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci data_fname_in = GET_ARG(); 129662306a36Sopenharmony_ci if (check_single_stdin(data_fname_in, ctx_fname_in)) 129762306a36Sopenharmony_ci return -1; 129862306a36Sopenharmony_ci } else if (is_prefix(*argv, "data_out")) { 129962306a36Sopenharmony_ci NEXT_ARG(); 130062306a36Sopenharmony_ci if (!REQ_ARGS(1)) 130162306a36Sopenharmony_ci return -1; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci data_fname_out = GET_ARG(); 130462306a36Sopenharmony_ci } else if (is_prefix(*argv, "data_size_out")) { 130562306a36Sopenharmony_ci char *endptr; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci NEXT_ARG(); 130862306a36Sopenharmony_ci if (!REQ_ARGS(1)) 130962306a36Sopenharmony_ci return -1; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci test_attr.data_size_out = strtoul(*argv, &endptr, 0); 131262306a36Sopenharmony_ci if (*endptr) { 131362306a36Sopenharmony_ci p_err("can't parse %s as output data size", 131462306a36Sopenharmony_ci *argv); 131562306a36Sopenharmony_ci return -1; 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci NEXT_ARG(); 131862306a36Sopenharmony_ci } else if (is_prefix(*argv, "ctx_in")) { 131962306a36Sopenharmony_ci NEXT_ARG(); 132062306a36Sopenharmony_ci if (!REQ_ARGS(1)) 132162306a36Sopenharmony_ci return -1; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci ctx_fname_in = GET_ARG(); 132462306a36Sopenharmony_ci if (check_single_stdin(data_fname_in, ctx_fname_in)) 132562306a36Sopenharmony_ci return -1; 132662306a36Sopenharmony_ci } else if (is_prefix(*argv, "ctx_out")) { 132762306a36Sopenharmony_ci NEXT_ARG(); 132862306a36Sopenharmony_ci if (!REQ_ARGS(1)) 132962306a36Sopenharmony_ci return -1; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci ctx_fname_out = GET_ARG(); 133262306a36Sopenharmony_ci } else if (is_prefix(*argv, "ctx_size_out")) { 133362306a36Sopenharmony_ci char *endptr; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci NEXT_ARG(); 133662306a36Sopenharmony_ci if (!REQ_ARGS(1)) 133762306a36Sopenharmony_ci return -1; 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci test_attr.ctx_size_out = strtoul(*argv, &endptr, 0); 134062306a36Sopenharmony_ci if (*endptr) { 134162306a36Sopenharmony_ci p_err("can't parse %s as output context size", 134262306a36Sopenharmony_ci *argv); 134362306a36Sopenharmony_ci return -1; 134462306a36Sopenharmony_ci } 134562306a36Sopenharmony_ci NEXT_ARG(); 134662306a36Sopenharmony_ci } else if (is_prefix(*argv, "repeat")) { 134762306a36Sopenharmony_ci char *endptr; 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_ci NEXT_ARG(); 135062306a36Sopenharmony_ci if (!REQ_ARGS(1)) 135162306a36Sopenharmony_ci return -1; 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci repeat = strtoul(*argv, &endptr, 0); 135462306a36Sopenharmony_ci if (*endptr) { 135562306a36Sopenharmony_ci p_err("can't parse %s as repeat number", 135662306a36Sopenharmony_ci *argv); 135762306a36Sopenharmony_ci return -1; 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci NEXT_ARG(); 136062306a36Sopenharmony_ci } else { 136162306a36Sopenharmony_ci p_err("expected no more arguments, 'data_in', 'data_out', 'data_size_out', 'ctx_in', 'ctx_out', 'ctx_size_out' or 'repeat', got: '%s'?", 136262306a36Sopenharmony_ci *argv); 136362306a36Sopenharmony_ci return -1; 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci err = get_run_data(data_fname_in, &data_in, &test_attr.data_size_in); 136862306a36Sopenharmony_ci if (err) 136962306a36Sopenharmony_ci return -1; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci if (data_in) { 137262306a36Sopenharmony_ci if (!test_attr.data_size_out) 137362306a36Sopenharmony_ci test_attr.data_size_out = default_size; 137462306a36Sopenharmony_ci err = alloc_run_data(&data_out, test_attr.data_size_out); 137562306a36Sopenharmony_ci if (err) 137662306a36Sopenharmony_ci goto free_data_in; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci err = get_run_data(ctx_fname_in, &ctx_in, &test_attr.ctx_size_in); 138062306a36Sopenharmony_ci if (err) 138162306a36Sopenharmony_ci goto free_data_out; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (ctx_in) { 138462306a36Sopenharmony_ci if (!test_attr.ctx_size_out) 138562306a36Sopenharmony_ci test_attr.ctx_size_out = default_size; 138662306a36Sopenharmony_ci err = alloc_run_data(&ctx_out, test_attr.ctx_size_out); 138762306a36Sopenharmony_ci if (err) 138862306a36Sopenharmony_ci goto free_ctx_in; 138962306a36Sopenharmony_ci } 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci test_attr.repeat = repeat; 139262306a36Sopenharmony_ci test_attr.data_in = data_in; 139362306a36Sopenharmony_ci test_attr.data_out = data_out; 139462306a36Sopenharmony_ci test_attr.ctx_in = ctx_in; 139562306a36Sopenharmony_ci test_attr.ctx_out = ctx_out; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci err = bpf_prog_test_run_opts(fd, &test_attr); 139862306a36Sopenharmony_ci if (err) { 139962306a36Sopenharmony_ci p_err("failed to run program: %s", strerror(errno)); 140062306a36Sopenharmony_ci goto free_ctx_out; 140162306a36Sopenharmony_ci } 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci err = 0; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (json_output) 140662306a36Sopenharmony_ci jsonw_start_object(json_wtr); /* root */ 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci /* Do not exit on errors occurring when printing output data/context, 140962306a36Sopenharmony_ci * we still want to print return value and duration for program run. 141062306a36Sopenharmony_ci */ 141162306a36Sopenharmony_ci if (test_attr.data_size_out) 141262306a36Sopenharmony_ci err += print_run_output(test_attr.data_out, 141362306a36Sopenharmony_ci test_attr.data_size_out, 141462306a36Sopenharmony_ci data_fname_out, "data_out"); 141562306a36Sopenharmony_ci if (test_attr.ctx_size_out) 141662306a36Sopenharmony_ci err += print_run_output(test_attr.ctx_out, 141762306a36Sopenharmony_ci test_attr.ctx_size_out, 141862306a36Sopenharmony_ci ctx_fname_out, "ctx_out"); 141962306a36Sopenharmony_ci 142062306a36Sopenharmony_ci if (json_output) { 142162306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "retval", test_attr.retval); 142262306a36Sopenharmony_ci jsonw_uint_field(json_wtr, "duration", test_attr.duration); 142362306a36Sopenharmony_ci jsonw_end_object(json_wtr); /* root */ 142462306a36Sopenharmony_ci } else { 142562306a36Sopenharmony_ci fprintf(stdout, "Return value: %u, duration%s: %uns\n", 142662306a36Sopenharmony_ci test_attr.retval, 142762306a36Sopenharmony_ci repeat > 1 ? " (average)" : "", test_attr.duration); 142862306a36Sopenharmony_ci } 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_cifree_ctx_out: 143162306a36Sopenharmony_ci free(ctx_out); 143262306a36Sopenharmony_cifree_ctx_in: 143362306a36Sopenharmony_ci free(ctx_in); 143462306a36Sopenharmony_cifree_data_out: 143562306a36Sopenharmony_ci free(data_out); 143662306a36Sopenharmony_cifree_data_in: 143762306a36Sopenharmony_ci free(data_in); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci return err; 144062306a36Sopenharmony_ci} 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_cistatic int 144362306a36Sopenharmony_ciget_prog_type_by_name(const char *name, enum bpf_prog_type *prog_type, 144462306a36Sopenharmony_ci enum bpf_attach_type *expected_attach_type) 144562306a36Sopenharmony_ci{ 144662306a36Sopenharmony_ci libbpf_print_fn_t print_backup; 144762306a36Sopenharmony_ci int ret; 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 145062306a36Sopenharmony_ci if (!ret) 145162306a36Sopenharmony_ci return ret; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci /* libbpf_prog_type_by_name() failed, let's re-run with debug level */ 145462306a36Sopenharmony_ci print_backup = libbpf_set_print(print_all_levels); 145562306a36Sopenharmony_ci ret = libbpf_prog_type_by_name(name, prog_type, expected_attach_type); 145662306a36Sopenharmony_ci libbpf_set_print(print_backup); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci return ret; 145962306a36Sopenharmony_ci} 146062306a36Sopenharmony_ci 146162306a36Sopenharmony_cistatic int 146262306a36Sopenharmony_ciauto_attach_program(struct bpf_program *prog, const char *path) 146362306a36Sopenharmony_ci{ 146462306a36Sopenharmony_ci struct bpf_link *link; 146562306a36Sopenharmony_ci int err; 146662306a36Sopenharmony_ci 146762306a36Sopenharmony_ci link = bpf_program__attach(prog); 146862306a36Sopenharmony_ci if (!link) { 146962306a36Sopenharmony_ci p_info("Program %s does not support autoattach, falling back to pinning", 147062306a36Sopenharmony_ci bpf_program__name(prog)); 147162306a36Sopenharmony_ci return bpf_obj_pin(bpf_program__fd(prog), path); 147262306a36Sopenharmony_ci } 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_ci err = bpf_link__pin(link, path); 147562306a36Sopenharmony_ci bpf_link__destroy(link); 147662306a36Sopenharmony_ci return err; 147762306a36Sopenharmony_ci} 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_cistatic int 148062306a36Sopenharmony_ciauto_attach_programs(struct bpf_object *obj, const char *path) 148162306a36Sopenharmony_ci{ 148262306a36Sopenharmony_ci struct bpf_program *prog; 148362306a36Sopenharmony_ci char buf[PATH_MAX]; 148462306a36Sopenharmony_ci int err; 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci bpf_object__for_each_program(prog, obj) { 148762306a36Sopenharmony_ci err = pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog)); 148862306a36Sopenharmony_ci if (err) 148962306a36Sopenharmony_ci goto err_unpin_programs; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci err = auto_attach_program(prog, buf); 149262306a36Sopenharmony_ci if (err) 149362306a36Sopenharmony_ci goto err_unpin_programs; 149462306a36Sopenharmony_ci } 149562306a36Sopenharmony_ci 149662306a36Sopenharmony_ci return 0; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_cierr_unpin_programs: 149962306a36Sopenharmony_ci while ((prog = bpf_object__prev_program(obj, prog))) { 150062306a36Sopenharmony_ci if (pathname_concat(buf, sizeof(buf), path, bpf_program__name(prog))) 150162306a36Sopenharmony_ci continue; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci bpf_program__unpin(prog, buf); 150462306a36Sopenharmony_ci } 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci return err; 150762306a36Sopenharmony_ci} 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_cistatic int load_with_options(int argc, char **argv, bool first_prog_only) 151062306a36Sopenharmony_ci{ 151162306a36Sopenharmony_ci enum bpf_prog_type common_prog_type = BPF_PROG_TYPE_UNSPEC; 151262306a36Sopenharmony_ci DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts, 151362306a36Sopenharmony_ci .relaxed_maps = relaxed_maps, 151462306a36Sopenharmony_ci ); 151562306a36Sopenharmony_ci enum bpf_attach_type expected_attach_type; 151662306a36Sopenharmony_ci struct map_replace *map_replace = NULL; 151762306a36Sopenharmony_ci struct bpf_program *prog = NULL, *pos; 151862306a36Sopenharmony_ci unsigned int old_map_fds = 0; 151962306a36Sopenharmony_ci const char *pinmaps = NULL; 152062306a36Sopenharmony_ci __u32 xdpmeta_ifindex = 0; 152162306a36Sopenharmony_ci __u32 offload_ifindex = 0; 152262306a36Sopenharmony_ci bool auto_attach = false; 152362306a36Sopenharmony_ci struct bpf_object *obj; 152462306a36Sopenharmony_ci struct bpf_map *map; 152562306a36Sopenharmony_ci const char *pinfile; 152662306a36Sopenharmony_ci unsigned int i, j; 152762306a36Sopenharmony_ci const char *file; 152862306a36Sopenharmony_ci int idx, err; 152962306a36Sopenharmony_ci 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci if (!REQ_ARGS(2)) 153262306a36Sopenharmony_ci return -1; 153362306a36Sopenharmony_ci file = GET_ARG(); 153462306a36Sopenharmony_ci pinfile = GET_ARG(); 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_ci while (argc) { 153762306a36Sopenharmony_ci if (is_prefix(*argv, "type")) { 153862306a36Sopenharmony_ci NEXT_ARG(); 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci if (common_prog_type != BPF_PROG_TYPE_UNSPEC) { 154162306a36Sopenharmony_ci p_err("program type already specified"); 154262306a36Sopenharmony_ci goto err_free_reuse_maps; 154362306a36Sopenharmony_ci } 154462306a36Sopenharmony_ci if (!REQ_ARGS(1)) 154562306a36Sopenharmony_ci goto err_free_reuse_maps; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci err = libbpf_prog_type_by_name(*argv, &common_prog_type, 154862306a36Sopenharmony_ci &expected_attach_type); 154962306a36Sopenharmony_ci if (err < 0) { 155062306a36Sopenharmony_ci /* Put a '/' at the end of type to appease libbpf */ 155162306a36Sopenharmony_ci char *type = malloc(strlen(*argv) + 2); 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci if (!type) { 155462306a36Sopenharmony_ci p_err("mem alloc failed"); 155562306a36Sopenharmony_ci goto err_free_reuse_maps; 155662306a36Sopenharmony_ci } 155762306a36Sopenharmony_ci *type = 0; 155862306a36Sopenharmony_ci strcat(type, *argv); 155962306a36Sopenharmony_ci strcat(type, "/"); 156062306a36Sopenharmony_ci 156162306a36Sopenharmony_ci err = get_prog_type_by_name(type, &common_prog_type, 156262306a36Sopenharmony_ci &expected_attach_type); 156362306a36Sopenharmony_ci free(type); 156462306a36Sopenharmony_ci if (err < 0) 156562306a36Sopenharmony_ci goto err_free_reuse_maps; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci NEXT_ARG(); 156962306a36Sopenharmony_ci } else if (is_prefix(*argv, "map")) { 157062306a36Sopenharmony_ci void *new_map_replace; 157162306a36Sopenharmony_ci char *endptr, *name; 157262306a36Sopenharmony_ci int fd; 157362306a36Sopenharmony_ci 157462306a36Sopenharmony_ci NEXT_ARG(); 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci if (!REQ_ARGS(4)) 157762306a36Sopenharmony_ci goto err_free_reuse_maps; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (is_prefix(*argv, "idx")) { 158062306a36Sopenharmony_ci NEXT_ARG(); 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci idx = strtoul(*argv, &endptr, 0); 158362306a36Sopenharmony_ci if (*endptr) { 158462306a36Sopenharmony_ci p_err("can't parse %s as IDX", *argv); 158562306a36Sopenharmony_ci goto err_free_reuse_maps; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci name = NULL; 158862306a36Sopenharmony_ci } else if (is_prefix(*argv, "name")) { 158962306a36Sopenharmony_ci NEXT_ARG(); 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci name = *argv; 159262306a36Sopenharmony_ci idx = -1; 159362306a36Sopenharmony_ci } else { 159462306a36Sopenharmony_ci p_err("expected 'idx' or 'name', got: '%s'?", 159562306a36Sopenharmony_ci *argv); 159662306a36Sopenharmony_ci goto err_free_reuse_maps; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci NEXT_ARG(); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci fd = map_parse_fd(&argc, &argv); 160162306a36Sopenharmony_ci if (fd < 0) 160262306a36Sopenharmony_ci goto err_free_reuse_maps; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci new_map_replace = libbpf_reallocarray(map_replace, 160562306a36Sopenharmony_ci old_map_fds + 1, 160662306a36Sopenharmony_ci sizeof(*map_replace)); 160762306a36Sopenharmony_ci if (!new_map_replace) { 160862306a36Sopenharmony_ci p_err("mem alloc failed"); 160962306a36Sopenharmony_ci goto err_free_reuse_maps; 161062306a36Sopenharmony_ci } 161162306a36Sopenharmony_ci map_replace = new_map_replace; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci map_replace[old_map_fds].idx = idx; 161462306a36Sopenharmony_ci map_replace[old_map_fds].name = name; 161562306a36Sopenharmony_ci map_replace[old_map_fds].fd = fd; 161662306a36Sopenharmony_ci old_map_fds++; 161762306a36Sopenharmony_ci } else if (is_prefix(*argv, "dev")) { 161862306a36Sopenharmony_ci p_info("Warning: 'bpftool prog load [...] dev <ifname>' syntax is deprecated.\n" 161962306a36Sopenharmony_ci "Going further, please use 'offload_dev <ifname>' to offload program to device.\n" 162062306a36Sopenharmony_ci "For applications using XDP hints only, use 'xdpmeta_dev <ifname>'."); 162162306a36Sopenharmony_ci goto offload_dev; 162262306a36Sopenharmony_ci } else if (is_prefix(*argv, "offload_dev")) { 162362306a36Sopenharmony_cioffload_dev: 162462306a36Sopenharmony_ci NEXT_ARG(); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci if (offload_ifindex) { 162762306a36Sopenharmony_ci p_err("offload_dev already specified"); 162862306a36Sopenharmony_ci goto err_free_reuse_maps; 162962306a36Sopenharmony_ci } else if (xdpmeta_ifindex) { 163062306a36Sopenharmony_ci p_err("xdpmeta_dev and offload_dev are mutually exclusive"); 163162306a36Sopenharmony_ci goto err_free_reuse_maps; 163262306a36Sopenharmony_ci } 163362306a36Sopenharmony_ci if (!REQ_ARGS(1)) 163462306a36Sopenharmony_ci goto err_free_reuse_maps; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci offload_ifindex = if_nametoindex(*argv); 163762306a36Sopenharmony_ci if (!offload_ifindex) { 163862306a36Sopenharmony_ci p_err("unrecognized netdevice '%s': %s", 163962306a36Sopenharmony_ci *argv, strerror(errno)); 164062306a36Sopenharmony_ci goto err_free_reuse_maps; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci NEXT_ARG(); 164362306a36Sopenharmony_ci } else if (is_prefix(*argv, "xdpmeta_dev")) { 164462306a36Sopenharmony_ci NEXT_ARG(); 164562306a36Sopenharmony_ci 164662306a36Sopenharmony_ci if (xdpmeta_ifindex) { 164762306a36Sopenharmony_ci p_err("xdpmeta_dev already specified"); 164862306a36Sopenharmony_ci goto err_free_reuse_maps; 164962306a36Sopenharmony_ci } else if (offload_ifindex) { 165062306a36Sopenharmony_ci p_err("xdpmeta_dev and offload_dev are mutually exclusive"); 165162306a36Sopenharmony_ci goto err_free_reuse_maps; 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci if (!REQ_ARGS(1)) 165462306a36Sopenharmony_ci goto err_free_reuse_maps; 165562306a36Sopenharmony_ci 165662306a36Sopenharmony_ci xdpmeta_ifindex = if_nametoindex(*argv); 165762306a36Sopenharmony_ci if (!xdpmeta_ifindex) { 165862306a36Sopenharmony_ci p_err("unrecognized netdevice '%s': %s", 165962306a36Sopenharmony_ci *argv, strerror(errno)); 166062306a36Sopenharmony_ci goto err_free_reuse_maps; 166162306a36Sopenharmony_ci } 166262306a36Sopenharmony_ci NEXT_ARG(); 166362306a36Sopenharmony_ci } else if (is_prefix(*argv, "pinmaps")) { 166462306a36Sopenharmony_ci NEXT_ARG(); 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci if (!REQ_ARGS(1)) 166762306a36Sopenharmony_ci goto err_free_reuse_maps; 166862306a36Sopenharmony_ci 166962306a36Sopenharmony_ci pinmaps = GET_ARG(); 167062306a36Sopenharmony_ci } else if (is_prefix(*argv, "autoattach")) { 167162306a36Sopenharmony_ci auto_attach = true; 167262306a36Sopenharmony_ci NEXT_ARG(); 167362306a36Sopenharmony_ci } else { 167462306a36Sopenharmony_ci p_err("expected no more arguments, 'type', 'map' or 'dev', got: '%s'?", 167562306a36Sopenharmony_ci *argv); 167662306a36Sopenharmony_ci goto err_free_reuse_maps; 167762306a36Sopenharmony_ci } 167862306a36Sopenharmony_ci } 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci set_max_rlimit(); 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci if (verifier_logs) 168362306a36Sopenharmony_ci /* log_level1 + log_level2 + stats, but not stable UAPI */ 168462306a36Sopenharmony_ci open_opts.kernel_log_level = 1 + 2 + 4; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci obj = bpf_object__open_file(file, &open_opts); 168762306a36Sopenharmony_ci if (!obj) { 168862306a36Sopenharmony_ci p_err("failed to open object file"); 168962306a36Sopenharmony_ci goto err_free_reuse_maps; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci bpf_object__for_each_program(pos, obj) { 169362306a36Sopenharmony_ci enum bpf_prog_type prog_type = common_prog_type; 169462306a36Sopenharmony_ci 169562306a36Sopenharmony_ci if (prog_type == BPF_PROG_TYPE_UNSPEC) { 169662306a36Sopenharmony_ci const char *sec_name = bpf_program__section_name(pos); 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci err = get_prog_type_by_name(sec_name, &prog_type, 169962306a36Sopenharmony_ci &expected_attach_type); 170062306a36Sopenharmony_ci if (err < 0) 170162306a36Sopenharmony_ci goto err_close_obj; 170262306a36Sopenharmony_ci } 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci if (prog_type == BPF_PROG_TYPE_XDP && xdpmeta_ifindex) { 170562306a36Sopenharmony_ci bpf_program__set_flags(pos, BPF_F_XDP_DEV_BOUND_ONLY); 170662306a36Sopenharmony_ci bpf_program__set_ifindex(pos, xdpmeta_ifindex); 170762306a36Sopenharmony_ci } else { 170862306a36Sopenharmony_ci bpf_program__set_ifindex(pos, offload_ifindex); 170962306a36Sopenharmony_ci } 171062306a36Sopenharmony_ci if (bpf_program__type(pos) != prog_type) 171162306a36Sopenharmony_ci bpf_program__set_type(pos, prog_type); 171262306a36Sopenharmony_ci bpf_program__set_expected_attach_type(pos, expected_attach_type); 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci qsort(map_replace, old_map_fds, sizeof(*map_replace), 171662306a36Sopenharmony_ci map_replace_compar); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci /* After the sort maps by name will be first on the list, because they 171962306a36Sopenharmony_ci * have idx == -1. Resolve them. 172062306a36Sopenharmony_ci */ 172162306a36Sopenharmony_ci j = 0; 172262306a36Sopenharmony_ci while (j < old_map_fds && map_replace[j].name) { 172362306a36Sopenharmony_ci i = 0; 172462306a36Sopenharmony_ci bpf_object__for_each_map(map, obj) { 172562306a36Sopenharmony_ci if (!strcmp(bpf_map__name(map), map_replace[j].name)) { 172662306a36Sopenharmony_ci map_replace[j].idx = i; 172762306a36Sopenharmony_ci break; 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci i++; 173062306a36Sopenharmony_ci } 173162306a36Sopenharmony_ci if (map_replace[j].idx == -1) { 173262306a36Sopenharmony_ci p_err("unable to find map '%s'", map_replace[j].name); 173362306a36Sopenharmony_ci goto err_close_obj; 173462306a36Sopenharmony_ci } 173562306a36Sopenharmony_ci j++; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci /* Resort if any names were resolved */ 173862306a36Sopenharmony_ci if (j) 173962306a36Sopenharmony_ci qsort(map_replace, old_map_fds, sizeof(*map_replace), 174062306a36Sopenharmony_ci map_replace_compar); 174162306a36Sopenharmony_ci 174262306a36Sopenharmony_ci /* Set ifindex and name reuse */ 174362306a36Sopenharmony_ci j = 0; 174462306a36Sopenharmony_ci idx = 0; 174562306a36Sopenharmony_ci bpf_object__for_each_map(map, obj) { 174662306a36Sopenharmony_ci if (bpf_map__type(map) != BPF_MAP_TYPE_PERF_EVENT_ARRAY) 174762306a36Sopenharmony_ci bpf_map__set_ifindex(map, offload_ifindex); 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci if (j < old_map_fds && idx == map_replace[j].idx) { 175062306a36Sopenharmony_ci err = bpf_map__reuse_fd(map, map_replace[j++].fd); 175162306a36Sopenharmony_ci if (err) { 175262306a36Sopenharmony_ci p_err("unable to set up map reuse: %d", err); 175362306a36Sopenharmony_ci goto err_close_obj; 175462306a36Sopenharmony_ci } 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci /* Next reuse wants to apply to the same map */ 175762306a36Sopenharmony_ci if (j < old_map_fds && map_replace[j].idx == idx) { 175862306a36Sopenharmony_ci p_err("replacement for map idx %d specified more than once", 175962306a36Sopenharmony_ci idx); 176062306a36Sopenharmony_ci goto err_close_obj; 176162306a36Sopenharmony_ci } 176262306a36Sopenharmony_ci } 176362306a36Sopenharmony_ci 176462306a36Sopenharmony_ci idx++; 176562306a36Sopenharmony_ci } 176662306a36Sopenharmony_ci if (j < old_map_fds) { 176762306a36Sopenharmony_ci p_err("map idx '%d' not used", map_replace[j].idx); 176862306a36Sopenharmony_ci goto err_close_obj; 176962306a36Sopenharmony_ci } 177062306a36Sopenharmony_ci 177162306a36Sopenharmony_ci err = bpf_object__load(obj); 177262306a36Sopenharmony_ci if (err) { 177362306a36Sopenharmony_ci p_err("failed to load object file"); 177462306a36Sopenharmony_ci goto err_close_obj; 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci err = mount_bpffs_for_pin(pinfile, !first_prog_only); 177862306a36Sopenharmony_ci if (err) 177962306a36Sopenharmony_ci goto err_close_obj; 178062306a36Sopenharmony_ci 178162306a36Sopenharmony_ci if (first_prog_only) { 178262306a36Sopenharmony_ci prog = bpf_object__next_program(obj, NULL); 178362306a36Sopenharmony_ci if (!prog) { 178462306a36Sopenharmony_ci p_err("object file doesn't contain any bpf program"); 178562306a36Sopenharmony_ci goto err_close_obj; 178662306a36Sopenharmony_ci } 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci if (auto_attach) 178962306a36Sopenharmony_ci err = auto_attach_program(prog, pinfile); 179062306a36Sopenharmony_ci else 179162306a36Sopenharmony_ci err = bpf_obj_pin(bpf_program__fd(prog), pinfile); 179262306a36Sopenharmony_ci if (err) { 179362306a36Sopenharmony_ci p_err("failed to pin program %s", 179462306a36Sopenharmony_ci bpf_program__section_name(prog)); 179562306a36Sopenharmony_ci goto err_close_obj; 179662306a36Sopenharmony_ci } 179762306a36Sopenharmony_ci } else { 179862306a36Sopenharmony_ci if (auto_attach) 179962306a36Sopenharmony_ci err = auto_attach_programs(obj, pinfile); 180062306a36Sopenharmony_ci else 180162306a36Sopenharmony_ci err = bpf_object__pin_programs(obj, pinfile); 180262306a36Sopenharmony_ci if (err) { 180362306a36Sopenharmony_ci p_err("failed to pin all programs"); 180462306a36Sopenharmony_ci goto err_close_obj; 180562306a36Sopenharmony_ci } 180662306a36Sopenharmony_ci } 180762306a36Sopenharmony_ci 180862306a36Sopenharmony_ci if (pinmaps) { 180962306a36Sopenharmony_ci err = bpf_object__pin_maps(obj, pinmaps); 181062306a36Sopenharmony_ci if (err) { 181162306a36Sopenharmony_ci p_err("failed to pin all maps"); 181262306a36Sopenharmony_ci goto err_unpin; 181362306a36Sopenharmony_ci } 181462306a36Sopenharmony_ci } 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci if (json_output) 181762306a36Sopenharmony_ci jsonw_null(json_wtr); 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci bpf_object__close(obj); 182062306a36Sopenharmony_ci for (i = 0; i < old_map_fds; i++) 182162306a36Sopenharmony_ci close(map_replace[i].fd); 182262306a36Sopenharmony_ci free(map_replace); 182362306a36Sopenharmony_ci 182462306a36Sopenharmony_ci return 0; 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_cierr_unpin: 182762306a36Sopenharmony_ci if (first_prog_only) 182862306a36Sopenharmony_ci unlink(pinfile); 182962306a36Sopenharmony_ci else 183062306a36Sopenharmony_ci bpf_object__unpin_programs(obj, pinfile); 183162306a36Sopenharmony_cierr_close_obj: 183262306a36Sopenharmony_ci bpf_object__close(obj); 183362306a36Sopenharmony_cierr_free_reuse_maps: 183462306a36Sopenharmony_ci for (i = 0; i < old_map_fds; i++) 183562306a36Sopenharmony_ci close(map_replace[i].fd); 183662306a36Sopenharmony_ci free(map_replace); 183762306a36Sopenharmony_ci return -1; 183862306a36Sopenharmony_ci} 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_cistatic int count_open_fds(void) 184162306a36Sopenharmony_ci{ 184262306a36Sopenharmony_ci DIR *dp = opendir("/proc/self/fd"); 184362306a36Sopenharmony_ci struct dirent *de; 184462306a36Sopenharmony_ci int cnt = -3; 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci if (!dp) 184762306a36Sopenharmony_ci return -1; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci while ((de = readdir(dp))) 185062306a36Sopenharmony_ci cnt++; 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci closedir(dp); 185362306a36Sopenharmony_ci return cnt; 185462306a36Sopenharmony_ci} 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_cistatic int try_loader(struct gen_loader_opts *gen) 185762306a36Sopenharmony_ci{ 185862306a36Sopenharmony_ci struct bpf_load_and_run_opts opts = {}; 185962306a36Sopenharmony_ci struct bpf_loader_ctx *ctx; 186062306a36Sopenharmony_ci int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc), 186162306a36Sopenharmony_ci sizeof(struct bpf_prog_desc)); 186262306a36Sopenharmony_ci int log_buf_sz = (1u << 24) - 1; 186362306a36Sopenharmony_ci int err, fds_before, fd_delta; 186462306a36Sopenharmony_ci char *log_buf = NULL; 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci ctx = alloca(ctx_sz); 186762306a36Sopenharmony_ci memset(ctx, 0, ctx_sz); 186862306a36Sopenharmony_ci ctx->sz = ctx_sz; 186962306a36Sopenharmony_ci if (verifier_logs) { 187062306a36Sopenharmony_ci ctx->log_level = 1 + 2 + 4; 187162306a36Sopenharmony_ci ctx->log_size = log_buf_sz; 187262306a36Sopenharmony_ci log_buf = malloc(log_buf_sz); 187362306a36Sopenharmony_ci if (!log_buf) 187462306a36Sopenharmony_ci return -ENOMEM; 187562306a36Sopenharmony_ci ctx->log_buf = (long) log_buf; 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci opts.ctx = ctx; 187862306a36Sopenharmony_ci opts.data = gen->data; 187962306a36Sopenharmony_ci opts.data_sz = gen->data_sz; 188062306a36Sopenharmony_ci opts.insns = gen->insns; 188162306a36Sopenharmony_ci opts.insns_sz = gen->insns_sz; 188262306a36Sopenharmony_ci fds_before = count_open_fds(); 188362306a36Sopenharmony_ci err = bpf_load_and_run(&opts); 188462306a36Sopenharmony_ci fd_delta = count_open_fds() - fds_before; 188562306a36Sopenharmony_ci if (err < 0 || verifier_logs) { 188662306a36Sopenharmony_ci fprintf(stderr, "err %d\n%s\n%s", err, opts.errstr, log_buf); 188762306a36Sopenharmony_ci if (fd_delta && err < 0) 188862306a36Sopenharmony_ci fprintf(stderr, "loader prog leaked %d FDs\n", 188962306a36Sopenharmony_ci fd_delta); 189062306a36Sopenharmony_ci } 189162306a36Sopenharmony_ci free(log_buf); 189262306a36Sopenharmony_ci return err; 189362306a36Sopenharmony_ci} 189462306a36Sopenharmony_ci 189562306a36Sopenharmony_cistatic int do_loader(int argc, char **argv) 189662306a36Sopenharmony_ci{ 189762306a36Sopenharmony_ci DECLARE_LIBBPF_OPTS(bpf_object_open_opts, open_opts); 189862306a36Sopenharmony_ci DECLARE_LIBBPF_OPTS(gen_loader_opts, gen); 189962306a36Sopenharmony_ci struct bpf_object *obj; 190062306a36Sopenharmony_ci const char *file; 190162306a36Sopenharmony_ci int err = 0; 190262306a36Sopenharmony_ci 190362306a36Sopenharmony_ci if (!REQ_ARGS(1)) 190462306a36Sopenharmony_ci return -1; 190562306a36Sopenharmony_ci file = GET_ARG(); 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci if (verifier_logs) 190862306a36Sopenharmony_ci /* log_level1 + log_level2 + stats, but not stable UAPI */ 190962306a36Sopenharmony_ci open_opts.kernel_log_level = 1 + 2 + 4; 191062306a36Sopenharmony_ci 191162306a36Sopenharmony_ci obj = bpf_object__open_file(file, &open_opts); 191262306a36Sopenharmony_ci if (!obj) { 191362306a36Sopenharmony_ci p_err("failed to open object file"); 191462306a36Sopenharmony_ci goto err_close_obj; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci err = bpf_object__gen_loader(obj, &gen); 191862306a36Sopenharmony_ci if (err) 191962306a36Sopenharmony_ci goto err_close_obj; 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci err = bpf_object__load(obj); 192262306a36Sopenharmony_ci if (err) { 192362306a36Sopenharmony_ci p_err("failed to load object file"); 192462306a36Sopenharmony_ci goto err_close_obj; 192562306a36Sopenharmony_ci } 192662306a36Sopenharmony_ci 192762306a36Sopenharmony_ci if (verifier_logs) { 192862306a36Sopenharmony_ci struct dump_data dd = {}; 192962306a36Sopenharmony_ci 193062306a36Sopenharmony_ci kernel_syms_load(&dd); 193162306a36Sopenharmony_ci dump_xlated_plain(&dd, (void *)gen.insns, gen.insns_sz, false, false); 193262306a36Sopenharmony_ci kernel_syms_destroy(&dd); 193362306a36Sopenharmony_ci } 193462306a36Sopenharmony_ci err = try_loader(&gen); 193562306a36Sopenharmony_cierr_close_obj: 193662306a36Sopenharmony_ci bpf_object__close(obj); 193762306a36Sopenharmony_ci return err; 193862306a36Sopenharmony_ci} 193962306a36Sopenharmony_ci 194062306a36Sopenharmony_cistatic int do_load(int argc, char **argv) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci if (use_loader) 194362306a36Sopenharmony_ci return do_loader(argc, argv); 194462306a36Sopenharmony_ci return load_with_options(argc, argv, true); 194562306a36Sopenharmony_ci} 194662306a36Sopenharmony_ci 194762306a36Sopenharmony_cistatic int do_loadall(int argc, char **argv) 194862306a36Sopenharmony_ci{ 194962306a36Sopenharmony_ci return load_with_options(argc, argv, false); 195062306a36Sopenharmony_ci} 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci#ifdef BPFTOOL_WITHOUT_SKELETONS 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_cistatic int do_profile(int argc, char **argv) 195562306a36Sopenharmony_ci{ 195662306a36Sopenharmony_ci p_err("bpftool prog profile command is not supported. Please build bpftool with clang >= 10.0.0"); 195762306a36Sopenharmony_ci return 0; 195862306a36Sopenharmony_ci} 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci#else /* BPFTOOL_WITHOUT_SKELETONS */ 196162306a36Sopenharmony_ci 196262306a36Sopenharmony_ci#include "profiler.skel.h" 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_cistruct profile_metric { 196562306a36Sopenharmony_ci const char *name; 196662306a36Sopenharmony_ci struct bpf_perf_event_value val; 196762306a36Sopenharmony_ci struct perf_event_attr attr; 196862306a36Sopenharmony_ci bool selected; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci /* calculate ratios like instructions per cycle */ 197162306a36Sopenharmony_ci const int ratio_metric; /* 0 for N/A, 1 for index 0 (cycles) */ 197262306a36Sopenharmony_ci const char *ratio_desc; 197362306a36Sopenharmony_ci const float ratio_mul; 197462306a36Sopenharmony_ci} metrics[] = { 197562306a36Sopenharmony_ci { 197662306a36Sopenharmony_ci .name = "cycles", 197762306a36Sopenharmony_ci .attr = { 197862306a36Sopenharmony_ci .type = PERF_TYPE_HARDWARE, 197962306a36Sopenharmony_ci .config = PERF_COUNT_HW_CPU_CYCLES, 198062306a36Sopenharmony_ci .exclude_user = 1, 198162306a36Sopenharmony_ci }, 198262306a36Sopenharmony_ci }, 198362306a36Sopenharmony_ci { 198462306a36Sopenharmony_ci .name = "instructions", 198562306a36Sopenharmony_ci .attr = { 198662306a36Sopenharmony_ci .type = PERF_TYPE_HARDWARE, 198762306a36Sopenharmony_ci .config = PERF_COUNT_HW_INSTRUCTIONS, 198862306a36Sopenharmony_ci .exclude_user = 1, 198962306a36Sopenharmony_ci }, 199062306a36Sopenharmony_ci .ratio_metric = 1, 199162306a36Sopenharmony_ci .ratio_desc = "insns per cycle", 199262306a36Sopenharmony_ci .ratio_mul = 1.0, 199362306a36Sopenharmony_ci }, 199462306a36Sopenharmony_ci { 199562306a36Sopenharmony_ci .name = "l1d_loads", 199662306a36Sopenharmony_ci .attr = { 199762306a36Sopenharmony_ci .type = PERF_TYPE_HW_CACHE, 199862306a36Sopenharmony_ci .config = 199962306a36Sopenharmony_ci PERF_COUNT_HW_CACHE_L1D | 200062306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_OP_READ << 8) | 200162306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_RESULT_ACCESS << 16), 200262306a36Sopenharmony_ci .exclude_user = 1, 200362306a36Sopenharmony_ci }, 200462306a36Sopenharmony_ci }, 200562306a36Sopenharmony_ci { 200662306a36Sopenharmony_ci .name = "llc_misses", 200762306a36Sopenharmony_ci .attr = { 200862306a36Sopenharmony_ci .type = PERF_TYPE_HW_CACHE, 200962306a36Sopenharmony_ci .config = 201062306a36Sopenharmony_ci PERF_COUNT_HW_CACHE_LL | 201162306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_OP_READ << 8) | 201262306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 201362306a36Sopenharmony_ci .exclude_user = 1 201462306a36Sopenharmony_ci }, 201562306a36Sopenharmony_ci .ratio_metric = 2, 201662306a36Sopenharmony_ci .ratio_desc = "LLC misses per million insns", 201762306a36Sopenharmony_ci .ratio_mul = 1e6, 201862306a36Sopenharmony_ci }, 201962306a36Sopenharmony_ci { 202062306a36Sopenharmony_ci .name = "itlb_misses", 202162306a36Sopenharmony_ci .attr = { 202262306a36Sopenharmony_ci .type = PERF_TYPE_HW_CACHE, 202362306a36Sopenharmony_ci .config = 202462306a36Sopenharmony_ci PERF_COUNT_HW_CACHE_ITLB | 202562306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_OP_READ << 8) | 202662306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 202762306a36Sopenharmony_ci .exclude_user = 1 202862306a36Sopenharmony_ci }, 202962306a36Sopenharmony_ci .ratio_metric = 2, 203062306a36Sopenharmony_ci .ratio_desc = "itlb misses per million insns", 203162306a36Sopenharmony_ci .ratio_mul = 1e6, 203262306a36Sopenharmony_ci }, 203362306a36Sopenharmony_ci { 203462306a36Sopenharmony_ci .name = "dtlb_misses", 203562306a36Sopenharmony_ci .attr = { 203662306a36Sopenharmony_ci .type = PERF_TYPE_HW_CACHE, 203762306a36Sopenharmony_ci .config = 203862306a36Sopenharmony_ci PERF_COUNT_HW_CACHE_DTLB | 203962306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_OP_READ << 8) | 204062306a36Sopenharmony_ci (PERF_COUNT_HW_CACHE_RESULT_MISS << 16), 204162306a36Sopenharmony_ci .exclude_user = 1 204262306a36Sopenharmony_ci }, 204362306a36Sopenharmony_ci .ratio_metric = 2, 204462306a36Sopenharmony_ci .ratio_desc = "dtlb misses per million insns", 204562306a36Sopenharmony_ci .ratio_mul = 1e6, 204662306a36Sopenharmony_ci }, 204762306a36Sopenharmony_ci}; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_cistatic __u64 profile_total_count; 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci#define MAX_NUM_PROFILE_METRICS 4 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_cistatic int profile_parse_metrics(int argc, char **argv) 205462306a36Sopenharmony_ci{ 205562306a36Sopenharmony_ci unsigned int metric_cnt; 205662306a36Sopenharmony_ci int selected_cnt = 0; 205762306a36Sopenharmony_ci unsigned int i; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci metric_cnt = ARRAY_SIZE(metrics); 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_ci while (argc > 0) { 206262306a36Sopenharmony_ci for (i = 0; i < metric_cnt; i++) { 206362306a36Sopenharmony_ci if (is_prefix(argv[0], metrics[i].name)) { 206462306a36Sopenharmony_ci if (!metrics[i].selected) 206562306a36Sopenharmony_ci selected_cnt++; 206662306a36Sopenharmony_ci metrics[i].selected = true; 206762306a36Sopenharmony_ci break; 206862306a36Sopenharmony_ci } 206962306a36Sopenharmony_ci } 207062306a36Sopenharmony_ci if (i == metric_cnt) { 207162306a36Sopenharmony_ci p_err("unknown metric %s", argv[0]); 207262306a36Sopenharmony_ci return -1; 207362306a36Sopenharmony_ci } 207462306a36Sopenharmony_ci NEXT_ARG(); 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci if (selected_cnt > MAX_NUM_PROFILE_METRICS) { 207762306a36Sopenharmony_ci p_err("too many (%d) metrics, please specify no more than %d metrics at at time", 207862306a36Sopenharmony_ci selected_cnt, MAX_NUM_PROFILE_METRICS); 207962306a36Sopenharmony_ci return -1; 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci return selected_cnt; 208262306a36Sopenharmony_ci} 208362306a36Sopenharmony_ci 208462306a36Sopenharmony_cistatic void profile_read_values(struct profiler_bpf *obj) 208562306a36Sopenharmony_ci{ 208662306a36Sopenharmony_ci __u32 m, cpu, num_cpu = obj->rodata->num_cpu; 208762306a36Sopenharmony_ci int reading_map_fd, count_map_fd; 208862306a36Sopenharmony_ci __u64 counts[num_cpu]; 208962306a36Sopenharmony_ci __u32 key = 0; 209062306a36Sopenharmony_ci int err; 209162306a36Sopenharmony_ci 209262306a36Sopenharmony_ci reading_map_fd = bpf_map__fd(obj->maps.accum_readings); 209362306a36Sopenharmony_ci count_map_fd = bpf_map__fd(obj->maps.counts); 209462306a36Sopenharmony_ci if (reading_map_fd < 0 || count_map_fd < 0) { 209562306a36Sopenharmony_ci p_err("failed to get fd for map"); 209662306a36Sopenharmony_ci return; 209762306a36Sopenharmony_ci } 209862306a36Sopenharmony_ci 209962306a36Sopenharmony_ci err = bpf_map_lookup_elem(count_map_fd, &key, counts); 210062306a36Sopenharmony_ci if (err) { 210162306a36Sopenharmony_ci p_err("failed to read count_map: %s", strerror(errno)); 210262306a36Sopenharmony_ci return; 210362306a36Sopenharmony_ci } 210462306a36Sopenharmony_ci 210562306a36Sopenharmony_ci profile_total_count = 0; 210662306a36Sopenharmony_ci for (cpu = 0; cpu < num_cpu; cpu++) 210762306a36Sopenharmony_ci profile_total_count += counts[cpu]; 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_ci for (m = 0; m < ARRAY_SIZE(metrics); m++) { 211062306a36Sopenharmony_ci struct bpf_perf_event_value values[num_cpu]; 211162306a36Sopenharmony_ci 211262306a36Sopenharmony_ci if (!metrics[m].selected) 211362306a36Sopenharmony_ci continue; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci err = bpf_map_lookup_elem(reading_map_fd, &key, values); 211662306a36Sopenharmony_ci if (err) { 211762306a36Sopenharmony_ci p_err("failed to read reading_map: %s", 211862306a36Sopenharmony_ci strerror(errno)); 211962306a36Sopenharmony_ci return; 212062306a36Sopenharmony_ci } 212162306a36Sopenharmony_ci for (cpu = 0; cpu < num_cpu; cpu++) { 212262306a36Sopenharmony_ci metrics[m].val.counter += values[cpu].counter; 212362306a36Sopenharmony_ci metrics[m].val.enabled += values[cpu].enabled; 212462306a36Sopenharmony_ci metrics[m].val.running += values[cpu].running; 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci key++; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cistatic void profile_print_readings_json(void) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci __u32 m; 213362306a36Sopenharmony_ci 213462306a36Sopenharmony_ci jsonw_start_array(json_wtr); 213562306a36Sopenharmony_ci for (m = 0; m < ARRAY_SIZE(metrics); m++) { 213662306a36Sopenharmony_ci if (!metrics[m].selected) 213762306a36Sopenharmony_ci continue; 213862306a36Sopenharmony_ci jsonw_start_object(json_wtr); 213962306a36Sopenharmony_ci jsonw_string_field(json_wtr, "metric", metrics[m].name); 214062306a36Sopenharmony_ci jsonw_lluint_field(json_wtr, "run_cnt", profile_total_count); 214162306a36Sopenharmony_ci jsonw_lluint_field(json_wtr, "value", metrics[m].val.counter); 214262306a36Sopenharmony_ci jsonw_lluint_field(json_wtr, "enabled", metrics[m].val.enabled); 214362306a36Sopenharmony_ci jsonw_lluint_field(json_wtr, "running", metrics[m].val.running); 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci jsonw_end_object(json_wtr); 214662306a36Sopenharmony_ci } 214762306a36Sopenharmony_ci jsonw_end_array(json_wtr); 214862306a36Sopenharmony_ci} 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_cistatic void profile_print_readings_plain(void) 215162306a36Sopenharmony_ci{ 215262306a36Sopenharmony_ci __u32 m; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci printf("\n%18llu %-20s\n", profile_total_count, "run_cnt"); 215562306a36Sopenharmony_ci for (m = 0; m < ARRAY_SIZE(metrics); m++) { 215662306a36Sopenharmony_ci struct bpf_perf_event_value *val = &metrics[m].val; 215762306a36Sopenharmony_ci int r; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci if (!metrics[m].selected) 216062306a36Sopenharmony_ci continue; 216162306a36Sopenharmony_ci printf("%18llu %-20s", val->counter, metrics[m].name); 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci r = metrics[m].ratio_metric - 1; 216462306a36Sopenharmony_ci if (r >= 0 && metrics[r].selected && 216562306a36Sopenharmony_ci metrics[r].val.counter > 0) { 216662306a36Sopenharmony_ci printf("# %8.2f %-30s", 216762306a36Sopenharmony_ci val->counter * metrics[m].ratio_mul / 216862306a36Sopenharmony_ci metrics[r].val.counter, 216962306a36Sopenharmony_ci metrics[m].ratio_desc); 217062306a36Sopenharmony_ci } else { 217162306a36Sopenharmony_ci printf("%-41s", ""); 217262306a36Sopenharmony_ci } 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci if (val->enabled > val->running) 217562306a36Sopenharmony_ci printf("(%4.2f%%)", 217662306a36Sopenharmony_ci val->running * 100.0 / val->enabled); 217762306a36Sopenharmony_ci printf("\n"); 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci} 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_cistatic void profile_print_readings(void) 218262306a36Sopenharmony_ci{ 218362306a36Sopenharmony_ci if (json_output) 218462306a36Sopenharmony_ci profile_print_readings_json(); 218562306a36Sopenharmony_ci else 218662306a36Sopenharmony_ci profile_print_readings_plain(); 218762306a36Sopenharmony_ci} 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_cistatic char *profile_target_name(int tgt_fd) 219062306a36Sopenharmony_ci{ 219162306a36Sopenharmony_ci struct bpf_func_info func_info; 219262306a36Sopenharmony_ci struct bpf_prog_info info = {}; 219362306a36Sopenharmony_ci __u32 info_len = sizeof(info); 219462306a36Sopenharmony_ci const struct btf_type *t; 219562306a36Sopenharmony_ci __u32 func_info_rec_size; 219662306a36Sopenharmony_ci struct btf *btf = NULL; 219762306a36Sopenharmony_ci char *name = NULL; 219862306a36Sopenharmony_ci int err; 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len); 220162306a36Sopenharmony_ci if (err) { 220262306a36Sopenharmony_ci p_err("failed to get info for prog FD %d", tgt_fd); 220362306a36Sopenharmony_ci goto out; 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci if (info.btf_id == 0) { 220762306a36Sopenharmony_ci p_err("prog FD %d doesn't have valid btf", tgt_fd); 220862306a36Sopenharmony_ci goto out; 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci func_info_rec_size = info.func_info_rec_size; 221262306a36Sopenharmony_ci if (info.nr_func_info == 0) { 221362306a36Sopenharmony_ci p_err("found 0 func_info for prog FD %d", tgt_fd); 221462306a36Sopenharmony_ci goto out; 221562306a36Sopenharmony_ci } 221662306a36Sopenharmony_ci 221762306a36Sopenharmony_ci memset(&info, 0, sizeof(info)); 221862306a36Sopenharmony_ci info.nr_func_info = 1; 221962306a36Sopenharmony_ci info.func_info_rec_size = func_info_rec_size; 222062306a36Sopenharmony_ci info.func_info = ptr_to_u64(&func_info); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci err = bpf_prog_get_info_by_fd(tgt_fd, &info, &info_len); 222362306a36Sopenharmony_ci if (err) { 222462306a36Sopenharmony_ci p_err("failed to get func_info for prog FD %d", tgt_fd); 222562306a36Sopenharmony_ci goto out; 222662306a36Sopenharmony_ci } 222762306a36Sopenharmony_ci 222862306a36Sopenharmony_ci btf = btf__load_from_kernel_by_id(info.btf_id); 222962306a36Sopenharmony_ci if (!btf) { 223062306a36Sopenharmony_ci p_err("failed to load btf for prog FD %d", tgt_fd); 223162306a36Sopenharmony_ci goto out; 223262306a36Sopenharmony_ci } 223362306a36Sopenharmony_ci 223462306a36Sopenharmony_ci t = btf__type_by_id(btf, func_info.type_id); 223562306a36Sopenharmony_ci if (!t) { 223662306a36Sopenharmony_ci p_err("btf %d doesn't have type %d", 223762306a36Sopenharmony_ci info.btf_id, func_info.type_id); 223862306a36Sopenharmony_ci goto out; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci name = strdup(btf__name_by_offset(btf, t->name_off)); 224162306a36Sopenharmony_ciout: 224262306a36Sopenharmony_ci btf__free(btf); 224362306a36Sopenharmony_ci return name; 224462306a36Sopenharmony_ci} 224562306a36Sopenharmony_ci 224662306a36Sopenharmony_cistatic struct profiler_bpf *profile_obj; 224762306a36Sopenharmony_cistatic int profile_tgt_fd = -1; 224862306a36Sopenharmony_cistatic char *profile_tgt_name; 224962306a36Sopenharmony_cistatic int *profile_perf_events; 225062306a36Sopenharmony_cistatic int profile_perf_event_cnt; 225162306a36Sopenharmony_ci 225262306a36Sopenharmony_cistatic void profile_close_perf_events(struct profiler_bpf *obj) 225362306a36Sopenharmony_ci{ 225462306a36Sopenharmony_ci int i; 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci for (i = profile_perf_event_cnt - 1; i >= 0; i--) 225762306a36Sopenharmony_ci close(profile_perf_events[i]); 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci free(profile_perf_events); 226062306a36Sopenharmony_ci profile_perf_event_cnt = 0; 226162306a36Sopenharmony_ci} 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_cistatic int profile_open_perf_event(int mid, int cpu, int map_fd) 226462306a36Sopenharmony_ci{ 226562306a36Sopenharmony_ci int pmu_fd; 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_ci pmu_fd = syscall(__NR_perf_event_open, &metrics[mid].attr, 226862306a36Sopenharmony_ci -1 /*pid*/, cpu, -1 /*group_fd*/, 0); 226962306a36Sopenharmony_ci if (pmu_fd < 0) { 227062306a36Sopenharmony_ci if (errno == ENODEV) { 227162306a36Sopenharmony_ci p_info("cpu %d may be offline, skip %s profiling.", 227262306a36Sopenharmony_ci cpu, metrics[mid].name); 227362306a36Sopenharmony_ci profile_perf_event_cnt++; 227462306a36Sopenharmony_ci return 0; 227562306a36Sopenharmony_ci } 227662306a36Sopenharmony_ci return -1; 227762306a36Sopenharmony_ci } 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci if (bpf_map_update_elem(map_fd, 228062306a36Sopenharmony_ci &profile_perf_event_cnt, 228162306a36Sopenharmony_ci &pmu_fd, BPF_ANY) || 228262306a36Sopenharmony_ci ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE, 0)) { 228362306a36Sopenharmony_ci close(pmu_fd); 228462306a36Sopenharmony_ci return -1; 228562306a36Sopenharmony_ci } 228662306a36Sopenharmony_ci 228762306a36Sopenharmony_ci profile_perf_events[profile_perf_event_cnt++] = pmu_fd; 228862306a36Sopenharmony_ci return 0; 228962306a36Sopenharmony_ci} 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_cistatic int profile_open_perf_events(struct profiler_bpf *obj) 229262306a36Sopenharmony_ci{ 229362306a36Sopenharmony_ci unsigned int cpu, m; 229462306a36Sopenharmony_ci int map_fd; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci profile_perf_events = calloc( 229762306a36Sopenharmony_ci obj->rodata->num_cpu * obj->rodata->num_metric, sizeof(int)); 229862306a36Sopenharmony_ci if (!profile_perf_events) { 229962306a36Sopenharmony_ci p_err("failed to allocate memory for perf_event array: %s", 230062306a36Sopenharmony_ci strerror(errno)); 230162306a36Sopenharmony_ci return -1; 230262306a36Sopenharmony_ci } 230362306a36Sopenharmony_ci map_fd = bpf_map__fd(obj->maps.events); 230462306a36Sopenharmony_ci if (map_fd < 0) { 230562306a36Sopenharmony_ci p_err("failed to get fd for events map"); 230662306a36Sopenharmony_ci return -1; 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci for (m = 0; m < ARRAY_SIZE(metrics); m++) { 231062306a36Sopenharmony_ci if (!metrics[m].selected) 231162306a36Sopenharmony_ci continue; 231262306a36Sopenharmony_ci for (cpu = 0; cpu < obj->rodata->num_cpu; cpu++) { 231362306a36Sopenharmony_ci if (profile_open_perf_event(m, cpu, map_fd)) { 231462306a36Sopenharmony_ci p_err("failed to create event %s on cpu %d", 231562306a36Sopenharmony_ci metrics[m].name, cpu); 231662306a36Sopenharmony_ci return -1; 231762306a36Sopenharmony_ci } 231862306a36Sopenharmony_ci } 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci return 0; 232162306a36Sopenharmony_ci} 232262306a36Sopenharmony_ci 232362306a36Sopenharmony_cistatic void profile_print_and_cleanup(void) 232462306a36Sopenharmony_ci{ 232562306a36Sopenharmony_ci profile_close_perf_events(profile_obj); 232662306a36Sopenharmony_ci profile_read_values(profile_obj); 232762306a36Sopenharmony_ci profile_print_readings(); 232862306a36Sopenharmony_ci profiler_bpf__destroy(profile_obj); 232962306a36Sopenharmony_ci 233062306a36Sopenharmony_ci close(profile_tgt_fd); 233162306a36Sopenharmony_ci free(profile_tgt_name); 233262306a36Sopenharmony_ci} 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_cistatic void int_exit(int signo) 233562306a36Sopenharmony_ci{ 233662306a36Sopenharmony_ci profile_print_and_cleanup(); 233762306a36Sopenharmony_ci exit(0); 233862306a36Sopenharmony_ci} 233962306a36Sopenharmony_ci 234062306a36Sopenharmony_cistatic int do_profile(int argc, char **argv) 234162306a36Sopenharmony_ci{ 234262306a36Sopenharmony_ci int num_metric, num_cpu, err = -1; 234362306a36Sopenharmony_ci struct bpf_program *prog; 234462306a36Sopenharmony_ci unsigned long duration; 234562306a36Sopenharmony_ci char *endptr; 234662306a36Sopenharmony_ci 234762306a36Sopenharmony_ci /* we at least need two args for the prog and one metric */ 234862306a36Sopenharmony_ci if (!REQ_ARGS(3)) 234962306a36Sopenharmony_ci return -EINVAL; 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci /* parse target fd */ 235262306a36Sopenharmony_ci profile_tgt_fd = prog_parse_fd(&argc, &argv); 235362306a36Sopenharmony_ci if (profile_tgt_fd < 0) { 235462306a36Sopenharmony_ci p_err("failed to parse fd"); 235562306a36Sopenharmony_ci return -1; 235662306a36Sopenharmony_ci } 235762306a36Sopenharmony_ci 235862306a36Sopenharmony_ci /* parse profiling optional duration */ 235962306a36Sopenharmony_ci if (argc > 2 && is_prefix(argv[0], "duration")) { 236062306a36Sopenharmony_ci NEXT_ARG(); 236162306a36Sopenharmony_ci duration = strtoul(*argv, &endptr, 0); 236262306a36Sopenharmony_ci if (*endptr) 236362306a36Sopenharmony_ci usage(); 236462306a36Sopenharmony_ci NEXT_ARG(); 236562306a36Sopenharmony_ci } else { 236662306a36Sopenharmony_ci duration = UINT_MAX; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci num_metric = profile_parse_metrics(argc, argv); 237062306a36Sopenharmony_ci if (num_metric <= 0) 237162306a36Sopenharmony_ci goto out; 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci num_cpu = libbpf_num_possible_cpus(); 237462306a36Sopenharmony_ci if (num_cpu <= 0) { 237562306a36Sopenharmony_ci p_err("failed to identify number of CPUs"); 237662306a36Sopenharmony_ci goto out; 237762306a36Sopenharmony_ci } 237862306a36Sopenharmony_ci 237962306a36Sopenharmony_ci profile_obj = profiler_bpf__open(); 238062306a36Sopenharmony_ci if (!profile_obj) { 238162306a36Sopenharmony_ci p_err("failed to open and/or load BPF object"); 238262306a36Sopenharmony_ci goto out; 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci profile_obj->rodata->num_cpu = num_cpu; 238662306a36Sopenharmony_ci profile_obj->rodata->num_metric = num_metric; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci /* adjust map sizes */ 238962306a36Sopenharmony_ci bpf_map__set_max_entries(profile_obj->maps.events, num_metric * num_cpu); 239062306a36Sopenharmony_ci bpf_map__set_max_entries(profile_obj->maps.fentry_readings, num_metric); 239162306a36Sopenharmony_ci bpf_map__set_max_entries(profile_obj->maps.accum_readings, num_metric); 239262306a36Sopenharmony_ci bpf_map__set_max_entries(profile_obj->maps.counts, 1); 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci /* change target name */ 239562306a36Sopenharmony_ci profile_tgt_name = profile_target_name(profile_tgt_fd); 239662306a36Sopenharmony_ci if (!profile_tgt_name) 239762306a36Sopenharmony_ci goto out; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci bpf_object__for_each_program(prog, profile_obj->obj) { 240062306a36Sopenharmony_ci err = bpf_program__set_attach_target(prog, profile_tgt_fd, 240162306a36Sopenharmony_ci profile_tgt_name); 240262306a36Sopenharmony_ci if (err) { 240362306a36Sopenharmony_ci p_err("failed to set attach target\n"); 240462306a36Sopenharmony_ci goto out; 240562306a36Sopenharmony_ci } 240662306a36Sopenharmony_ci } 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci set_max_rlimit(); 240962306a36Sopenharmony_ci err = profiler_bpf__load(profile_obj); 241062306a36Sopenharmony_ci if (err) { 241162306a36Sopenharmony_ci p_err("failed to load profile_obj"); 241262306a36Sopenharmony_ci goto out; 241362306a36Sopenharmony_ci } 241462306a36Sopenharmony_ci 241562306a36Sopenharmony_ci err = profile_open_perf_events(profile_obj); 241662306a36Sopenharmony_ci if (err) 241762306a36Sopenharmony_ci goto out; 241862306a36Sopenharmony_ci 241962306a36Sopenharmony_ci err = profiler_bpf__attach(profile_obj); 242062306a36Sopenharmony_ci if (err) { 242162306a36Sopenharmony_ci p_err("failed to attach profile_obj"); 242262306a36Sopenharmony_ci goto out; 242362306a36Sopenharmony_ci } 242462306a36Sopenharmony_ci signal(SIGINT, int_exit); 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci sleep(duration); 242762306a36Sopenharmony_ci profile_print_and_cleanup(); 242862306a36Sopenharmony_ci return 0; 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ciout: 243162306a36Sopenharmony_ci profile_close_perf_events(profile_obj); 243262306a36Sopenharmony_ci if (profile_obj) 243362306a36Sopenharmony_ci profiler_bpf__destroy(profile_obj); 243462306a36Sopenharmony_ci close(profile_tgt_fd); 243562306a36Sopenharmony_ci free(profile_tgt_name); 243662306a36Sopenharmony_ci return err; 243762306a36Sopenharmony_ci} 243862306a36Sopenharmony_ci 243962306a36Sopenharmony_ci#endif /* BPFTOOL_WITHOUT_SKELETONS */ 244062306a36Sopenharmony_ci 244162306a36Sopenharmony_cistatic int do_help(int argc, char **argv) 244262306a36Sopenharmony_ci{ 244362306a36Sopenharmony_ci if (json_output) { 244462306a36Sopenharmony_ci jsonw_null(json_wtr); 244562306a36Sopenharmony_ci return 0; 244662306a36Sopenharmony_ci } 244762306a36Sopenharmony_ci 244862306a36Sopenharmony_ci fprintf(stderr, 244962306a36Sopenharmony_ci "Usage: %1$s %2$s { show | list } [PROG]\n" 245062306a36Sopenharmony_ci " %1$s %2$s dump xlated PROG [{ file FILE | [opcodes] [linum] [visual] }]\n" 245162306a36Sopenharmony_ci " %1$s %2$s dump jited PROG [{ file FILE | [opcodes] [linum] }]\n" 245262306a36Sopenharmony_ci " %1$s %2$s pin PROG FILE\n" 245362306a36Sopenharmony_ci " %1$s %2$s { load | loadall } OBJ PATH \\\n" 245462306a36Sopenharmony_ci " [type TYPE] [{ offload_dev | xdpmeta_dev } NAME] \\\n" 245562306a36Sopenharmony_ci " [map { idx IDX | name NAME } MAP]\\\n" 245662306a36Sopenharmony_ci " [pinmaps MAP_DIR]\n" 245762306a36Sopenharmony_ci " [autoattach]\n" 245862306a36Sopenharmony_ci " %1$s %2$s attach PROG ATTACH_TYPE [MAP]\n" 245962306a36Sopenharmony_ci " %1$s %2$s detach PROG ATTACH_TYPE [MAP]\n" 246062306a36Sopenharmony_ci " %1$s %2$s run PROG \\\n" 246162306a36Sopenharmony_ci " data_in FILE \\\n" 246262306a36Sopenharmony_ci " [data_out FILE [data_size_out L]] \\\n" 246362306a36Sopenharmony_ci " [ctx_in FILE [ctx_out FILE [ctx_size_out M]]] \\\n" 246462306a36Sopenharmony_ci " [repeat N]\n" 246562306a36Sopenharmony_ci " %1$s %2$s profile PROG [duration DURATION] METRICs\n" 246662306a36Sopenharmony_ci " %1$s %2$s tracelog\n" 246762306a36Sopenharmony_ci " %1$s %2$s help\n" 246862306a36Sopenharmony_ci "\n" 246962306a36Sopenharmony_ci " " HELP_SPEC_MAP "\n" 247062306a36Sopenharmony_ci " " HELP_SPEC_PROGRAM "\n" 247162306a36Sopenharmony_ci " TYPE := { socket | kprobe | kretprobe | classifier | action |\n" 247262306a36Sopenharmony_ci " tracepoint | raw_tracepoint | xdp | perf_event | cgroup/skb |\n" 247362306a36Sopenharmony_ci " cgroup/sock | cgroup/dev | lwt_in | lwt_out | lwt_xmit |\n" 247462306a36Sopenharmony_ci " lwt_seg6local | sockops | sk_skb | sk_msg | lirc_mode2 |\n" 247562306a36Sopenharmony_ci " sk_reuseport | flow_dissector | cgroup/sysctl |\n" 247662306a36Sopenharmony_ci " cgroup/bind4 | cgroup/bind6 | cgroup/post_bind4 |\n" 247762306a36Sopenharmony_ci " cgroup/post_bind6 | cgroup/connect4 | cgroup/connect6 |\n" 247862306a36Sopenharmony_ci " cgroup/getpeername4 | cgroup/getpeername6 |\n" 247962306a36Sopenharmony_ci " cgroup/getsockname4 | cgroup/getsockname6 | cgroup/sendmsg4 |\n" 248062306a36Sopenharmony_ci " cgroup/sendmsg6 | cgroup/recvmsg4 | cgroup/recvmsg6 |\n" 248162306a36Sopenharmony_ci " cgroup/getsockopt | cgroup/setsockopt | cgroup/sock_release |\n" 248262306a36Sopenharmony_ci " struct_ops | fentry | fexit | freplace | sk_lookup }\n" 248362306a36Sopenharmony_ci " ATTACH_TYPE := { sk_msg_verdict | sk_skb_verdict | sk_skb_stream_verdict |\n" 248462306a36Sopenharmony_ci " sk_skb_stream_parser | flow_dissector }\n" 248562306a36Sopenharmony_ci " METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n" 248662306a36Sopenharmony_ci " " HELP_SPEC_OPTIONS " |\n" 248762306a36Sopenharmony_ci " {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n" 248862306a36Sopenharmony_ci " {-L|--use-loader} }\n" 248962306a36Sopenharmony_ci "", 249062306a36Sopenharmony_ci bin_name, argv[-2]); 249162306a36Sopenharmony_ci 249262306a36Sopenharmony_ci return 0; 249362306a36Sopenharmony_ci} 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_cistatic const struct cmd cmds[] = { 249662306a36Sopenharmony_ci { "show", do_show }, 249762306a36Sopenharmony_ci { "list", do_show }, 249862306a36Sopenharmony_ci { "help", do_help }, 249962306a36Sopenharmony_ci { "dump", do_dump }, 250062306a36Sopenharmony_ci { "pin", do_pin }, 250162306a36Sopenharmony_ci { "load", do_load }, 250262306a36Sopenharmony_ci { "loadall", do_loadall }, 250362306a36Sopenharmony_ci { "attach", do_attach }, 250462306a36Sopenharmony_ci { "detach", do_detach }, 250562306a36Sopenharmony_ci { "tracelog", do_tracelog }, 250662306a36Sopenharmony_ci { "run", do_run }, 250762306a36Sopenharmony_ci { "profile", do_profile }, 250862306a36Sopenharmony_ci { 0 } 250962306a36Sopenharmony_ci}; 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_ciint do_prog(int argc, char **argv) 251262306a36Sopenharmony_ci{ 251362306a36Sopenharmony_ci return cmd_select(cmds, argc, argv, do_help); 251462306a36Sopenharmony_ci} 2515