162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <errno.h> 362306a36Sopenharmony_ci#include <stdlib.h> 462306a36Sopenharmony_ci#include <bpf/bpf.h> 562306a36Sopenharmony_ci#include <bpf/btf.h> 662306a36Sopenharmony_ci#include <bpf/libbpf.h> 762306a36Sopenharmony_ci#include <linux/btf.h> 862306a36Sopenharmony_ci#include <linux/err.h> 962306a36Sopenharmony_ci#include <linux/string.h> 1062306a36Sopenharmony_ci#include <internal/lib.h> 1162306a36Sopenharmony_ci#include <symbol/kallsyms.h> 1262306a36Sopenharmony_ci#include "bpf-event.h" 1362306a36Sopenharmony_ci#include "bpf-utils.h" 1462306a36Sopenharmony_ci#include "debug.h" 1562306a36Sopenharmony_ci#include "dso.h" 1662306a36Sopenharmony_ci#include "symbol.h" 1762306a36Sopenharmony_ci#include "machine.h" 1862306a36Sopenharmony_ci#include "env.h" 1962306a36Sopenharmony_ci#include "session.h" 2062306a36Sopenharmony_ci#include "map.h" 2162306a36Sopenharmony_ci#include "evlist.h" 2262306a36Sopenharmony_ci#include "record.h" 2362306a36Sopenharmony_ci#include "util/synthetic-events.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci int ret = 0; 2862306a36Sopenharmony_ci size_t i; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci for (i = 0; i < len; i++) 3162306a36Sopenharmony_ci ret += snprintf(buf + ret, size - ret, "%02x", data[i]); 3262306a36Sopenharmony_ci return ret; 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic int machine__process_bpf_event_load(struct machine *machine, 3662306a36Sopenharmony_ci union perf_event *event, 3762306a36Sopenharmony_ci struct perf_sample *sample __maybe_unused) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci struct bpf_prog_info_node *info_node; 4062306a36Sopenharmony_ci struct perf_env *env = machine->env; 4162306a36Sopenharmony_ci struct perf_bpil *info_linear; 4262306a36Sopenharmony_ci int id = event->bpf.id; 4362306a36Sopenharmony_ci unsigned int i; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci /* perf-record, no need to handle bpf-event */ 4662306a36Sopenharmony_ci if (env == NULL) 4762306a36Sopenharmony_ci return 0; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci info_node = perf_env__find_bpf_prog_info(env, id); 5062306a36Sopenharmony_ci if (!info_node) 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci info_linear = info_node->info_linear; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) { 5562306a36Sopenharmony_ci u64 *addrs = (u64 *)(uintptr_t)(info_linear->info.jited_ksyms); 5662306a36Sopenharmony_ci u64 addr = addrs[i]; 5762306a36Sopenharmony_ci struct map *map = maps__find(machine__kernel_maps(machine), addr); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (map) { 6062306a36Sopenharmony_ci struct dso *dso = map__dso(map); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci dso->binary_type = DSO_BINARY_TYPE__BPF_PROG_INFO; 6362306a36Sopenharmony_ci dso->bpf_prog.id = id; 6462306a36Sopenharmony_ci dso->bpf_prog.sub_id = i; 6562306a36Sopenharmony_ci dso->bpf_prog.env = env; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci return 0; 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ciint machine__process_bpf(struct machine *machine, union perf_event *event, 7262306a36Sopenharmony_ci struct perf_sample *sample) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci if (dump_trace) 7562306a36Sopenharmony_ci perf_event__fprintf_bpf(event, stdout); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci switch (event->bpf.type) { 7862306a36Sopenharmony_ci case PERF_BPF_EVENT_PROG_LOAD: 7962306a36Sopenharmony_ci return machine__process_bpf_event_load(machine, event, sample); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci case PERF_BPF_EVENT_PROG_UNLOAD: 8262306a36Sopenharmony_ci /* 8362306a36Sopenharmony_ci * Do not free bpf_prog_info and btf of the program here, 8462306a36Sopenharmony_ci * as annotation still need them. They will be freed at 8562306a36Sopenharmony_ci * the end of the session. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci default: 8962306a36Sopenharmony_ci pr_debug("unexpected bpf event type of %d\n", event->bpf.type); 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic int perf_env__fetch_btf(struct perf_env *env, 9662306a36Sopenharmony_ci u32 btf_id, 9762306a36Sopenharmony_ci struct btf *btf) 9862306a36Sopenharmony_ci{ 9962306a36Sopenharmony_ci struct btf_node *node; 10062306a36Sopenharmony_ci u32 data_size; 10162306a36Sopenharmony_ci const void *data; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci data = btf__raw_data(btf, &data_size); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci node = malloc(data_size + sizeof(struct btf_node)); 10662306a36Sopenharmony_ci if (!node) 10762306a36Sopenharmony_ci return -1; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci node->id = btf_id; 11062306a36Sopenharmony_ci node->data_size = data_size; 11162306a36Sopenharmony_ci memcpy(node->data, data, data_size); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci if (!perf_env__insert_btf(env, node)) { 11462306a36Sopenharmony_ci /* Insertion failed because of a duplicate. */ 11562306a36Sopenharmony_ci free(node); 11662306a36Sopenharmony_ci return -1; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_cistatic int synthesize_bpf_prog_name(char *buf, int size, 12262306a36Sopenharmony_ci struct bpf_prog_info *info, 12362306a36Sopenharmony_ci struct btf *btf, 12462306a36Sopenharmony_ci u32 sub_id) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(uintptr_t)(info->prog_tags); 12762306a36Sopenharmony_ci void *func_infos = (void *)(uintptr_t)(info->func_info); 12862306a36Sopenharmony_ci u32 sub_prog_cnt = info->nr_jited_ksyms; 12962306a36Sopenharmony_ci const struct bpf_func_info *finfo; 13062306a36Sopenharmony_ci const char *short_name = NULL; 13162306a36Sopenharmony_ci const struct btf_type *t; 13262306a36Sopenharmony_ci int name_len; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci name_len = snprintf(buf, size, "bpf_prog_"); 13562306a36Sopenharmony_ci name_len += snprintf_hex(buf + name_len, size - name_len, 13662306a36Sopenharmony_ci prog_tags[sub_id], BPF_TAG_SIZE); 13762306a36Sopenharmony_ci if (btf) { 13862306a36Sopenharmony_ci finfo = func_infos + sub_id * info->func_info_rec_size; 13962306a36Sopenharmony_ci t = btf__type_by_id(btf, finfo->type_id); 14062306a36Sopenharmony_ci short_name = btf__name_by_offset(btf, t->name_off); 14162306a36Sopenharmony_ci } else if (sub_id == 0 && sub_prog_cnt == 1) { 14262306a36Sopenharmony_ci /* no subprog */ 14362306a36Sopenharmony_ci if (info->name[0]) 14462306a36Sopenharmony_ci short_name = info->name; 14562306a36Sopenharmony_ci } else 14662306a36Sopenharmony_ci short_name = "F"; 14762306a36Sopenharmony_ci if (short_name) 14862306a36Sopenharmony_ci name_len += snprintf(buf + name_len, size - name_len, 14962306a36Sopenharmony_ci "_%s", short_name); 15062306a36Sopenharmony_ci return name_len; 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf 15562306a36Sopenharmony_ci * program. One PERF_RECORD_BPF_EVENT is generated for the program. And 15662306a36Sopenharmony_ci * one PERF_RECORD_KSYMBOL is generated for each sub program. 15762306a36Sopenharmony_ci * 15862306a36Sopenharmony_ci * Returns: 15962306a36Sopenharmony_ci * 0 for success; 16062306a36Sopenharmony_ci * -1 for failures; 16162306a36Sopenharmony_ci * -2 for lack of kernel support. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic int perf_event__synthesize_one_bpf_prog(struct perf_session *session, 16462306a36Sopenharmony_ci perf_event__handler_t process, 16562306a36Sopenharmony_ci struct machine *machine, 16662306a36Sopenharmony_ci int fd, 16762306a36Sopenharmony_ci union perf_event *event, 16862306a36Sopenharmony_ci struct record_opts *opts) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci struct perf_record_ksymbol *ksymbol_event = &event->ksymbol; 17162306a36Sopenharmony_ci struct perf_record_bpf_event *bpf_event = &event->bpf; 17262306a36Sopenharmony_ci struct perf_tool *tool = session->tool; 17362306a36Sopenharmony_ci struct bpf_prog_info_node *info_node; 17462306a36Sopenharmony_ci struct perf_bpil *info_linear; 17562306a36Sopenharmony_ci struct bpf_prog_info *info; 17662306a36Sopenharmony_ci struct btf *btf = NULL; 17762306a36Sopenharmony_ci struct perf_env *env; 17862306a36Sopenharmony_ci u32 sub_prog_cnt, i; 17962306a36Sopenharmony_ci int err = 0; 18062306a36Sopenharmony_ci u64 arrays; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci /* 18362306a36Sopenharmony_ci * for perf-record and perf-report use header.env; 18462306a36Sopenharmony_ci * otherwise, use global perf_env. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci env = session->data ? &session->header.env : &perf_env; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci arrays = 1UL << PERF_BPIL_JITED_KSYMS; 18962306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_JITED_FUNC_LENS; 19062306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_FUNC_INFO; 19162306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_PROG_TAGS; 19262306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_JITED_INSNS; 19362306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_LINE_INFO; 19462306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_JITED_LINE_INFO; 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci info_linear = get_bpf_prog_info_linear(fd, arrays); 19762306a36Sopenharmony_ci if (IS_ERR_OR_NULL(info_linear)) { 19862306a36Sopenharmony_ci info_linear = NULL; 19962306a36Sopenharmony_ci pr_debug("%s: failed to get BPF program info. aborting\n", __func__); 20062306a36Sopenharmony_ci return -1; 20162306a36Sopenharmony_ci } 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci if (info_linear->info_len < offsetof(struct bpf_prog_info, prog_tags)) { 20462306a36Sopenharmony_ci free(info_linear); 20562306a36Sopenharmony_ci pr_debug("%s: the kernel is too old, aborting\n", __func__); 20662306a36Sopenharmony_ci return -2; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci info = &info_linear->info; 21062306a36Sopenharmony_ci if (!info->jited_ksyms) { 21162306a36Sopenharmony_ci free(info_linear); 21262306a36Sopenharmony_ci return -1; 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* number of ksyms, func_lengths, and tags should match */ 21662306a36Sopenharmony_ci sub_prog_cnt = info->nr_jited_ksyms; 21762306a36Sopenharmony_ci if (sub_prog_cnt != info->nr_prog_tags || 21862306a36Sopenharmony_ci sub_prog_cnt != info->nr_jited_func_lens) { 21962306a36Sopenharmony_ci free(info_linear); 22062306a36Sopenharmony_ci return -1; 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci /* check BTF func info support */ 22462306a36Sopenharmony_ci if (info->btf_id && info->nr_func_info && info->func_info_rec_size) { 22562306a36Sopenharmony_ci /* btf func info number should be same as sub_prog_cnt */ 22662306a36Sopenharmony_ci if (sub_prog_cnt != info->nr_func_info) { 22762306a36Sopenharmony_ci pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__); 22862306a36Sopenharmony_ci free(info_linear); 22962306a36Sopenharmony_ci return -1; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci btf = btf__load_from_kernel_by_id(info->btf_id); 23262306a36Sopenharmony_ci if (libbpf_get_error(btf)) { 23362306a36Sopenharmony_ci pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info->btf_id); 23462306a36Sopenharmony_ci err = -1; 23562306a36Sopenharmony_ci goto out; 23662306a36Sopenharmony_ci } 23762306a36Sopenharmony_ci perf_env__fetch_btf(env, info->btf_id, btf); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Synthesize PERF_RECORD_KSYMBOL */ 24162306a36Sopenharmony_ci for (i = 0; i < sub_prog_cnt; i++) { 24262306a36Sopenharmony_ci __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens); 24362306a36Sopenharmony_ci __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms); 24462306a36Sopenharmony_ci int name_len; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci *ksymbol_event = (struct perf_record_ksymbol) { 24762306a36Sopenharmony_ci .header = { 24862306a36Sopenharmony_ci .type = PERF_RECORD_KSYMBOL, 24962306a36Sopenharmony_ci .size = offsetof(struct perf_record_ksymbol, name), 25062306a36Sopenharmony_ci }, 25162306a36Sopenharmony_ci .addr = prog_addrs[i], 25262306a36Sopenharmony_ci .len = prog_lens[i], 25362306a36Sopenharmony_ci .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF, 25462306a36Sopenharmony_ci .flags = 0, 25562306a36Sopenharmony_ci }; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci name_len = synthesize_bpf_prog_name(ksymbol_event->name, 25862306a36Sopenharmony_ci KSYM_NAME_LEN, info, btf, i); 25962306a36Sopenharmony_ci ksymbol_event->header.size += PERF_ALIGN(name_len + 1, 26062306a36Sopenharmony_ci sizeof(u64)); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci memset((void *)event + event->header.size, 0, machine->id_hdr_size); 26362306a36Sopenharmony_ci event->header.size += machine->id_hdr_size; 26462306a36Sopenharmony_ci err = perf_tool__process_synth_event(tool, event, 26562306a36Sopenharmony_ci machine, process); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!opts->no_bpf_event) { 26962306a36Sopenharmony_ci /* Synthesize PERF_RECORD_BPF_EVENT */ 27062306a36Sopenharmony_ci *bpf_event = (struct perf_record_bpf_event) { 27162306a36Sopenharmony_ci .header = { 27262306a36Sopenharmony_ci .type = PERF_RECORD_BPF_EVENT, 27362306a36Sopenharmony_ci .size = sizeof(struct perf_record_bpf_event), 27462306a36Sopenharmony_ci }, 27562306a36Sopenharmony_ci .type = PERF_BPF_EVENT_PROG_LOAD, 27662306a36Sopenharmony_ci .flags = 0, 27762306a36Sopenharmony_ci .id = info->id, 27862306a36Sopenharmony_ci }; 27962306a36Sopenharmony_ci memcpy(bpf_event->tag, info->tag, BPF_TAG_SIZE); 28062306a36Sopenharmony_ci memset((void *)event + event->header.size, 0, machine->id_hdr_size); 28162306a36Sopenharmony_ci event->header.size += machine->id_hdr_size; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci /* save bpf_prog_info to env */ 28462306a36Sopenharmony_ci info_node = malloc(sizeof(struct bpf_prog_info_node)); 28562306a36Sopenharmony_ci if (!info_node) { 28662306a36Sopenharmony_ci err = -1; 28762306a36Sopenharmony_ci goto out; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci info_node->info_linear = info_linear; 29162306a36Sopenharmony_ci perf_env__insert_bpf_prog_info(env, info_node); 29262306a36Sopenharmony_ci info_linear = NULL; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* 29562306a36Sopenharmony_ci * process after saving bpf_prog_info to env, so that 29662306a36Sopenharmony_ci * required information is ready for look up 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci err = perf_tool__process_synth_event(tool, event, 29962306a36Sopenharmony_ci machine, process); 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ciout: 30362306a36Sopenharmony_ci free(info_linear); 30462306a36Sopenharmony_ci btf__free(btf); 30562306a36Sopenharmony_ci return err ? -1 : 0; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistruct kallsyms_parse { 30962306a36Sopenharmony_ci union perf_event *event; 31062306a36Sopenharmony_ci perf_event__handler_t process; 31162306a36Sopenharmony_ci struct machine *machine; 31262306a36Sopenharmony_ci struct perf_tool *tool; 31362306a36Sopenharmony_ci}; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int 31662306a36Sopenharmony_ciprocess_bpf_image(char *name, u64 addr, struct kallsyms_parse *data) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct machine *machine = data->machine; 31962306a36Sopenharmony_ci union perf_event *event = data->event; 32062306a36Sopenharmony_ci struct perf_record_ksymbol *ksymbol; 32162306a36Sopenharmony_ci int len; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ksymbol = &event->ksymbol; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci *ksymbol = (struct perf_record_ksymbol) { 32662306a36Sopenharmony_ci .header = { 32762306a36Sopenharmony_ci .type = PERF_RECORD_KSYMBOL, 32862306a36Sopenharmony_ci .size = offsetof(struct perf_record_ksymbol, name), 32962306a36Sopenharmony_ci }, 33062306a36Sopenharmony_ci .addr = addr, 33162306a36Sopenharmony_ci .len = page_size, 33262306a36Sopenharmony_ci .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF, 33362306a36Sopenharmony_ci .flags = 0, 33462306a36Sopenharmony_ci }; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci len = scnprintf(ksymbol->name, KSYM_NAME_LEN, "%s", name); 33762306a36Sopenharmony_ci ksymbol->header.size += PERF_ALIGN(len + 1, sizeof(u64)); 33862306a36Sopenharmony_ci memset((void *) event + event->header.size, 0, machine->id_hdr_size); 33962306a36Sopenharmony_ci event->header.size += machine->id_hdr_size; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci return perf_tool__process_synth_event(data->tool, event, machine, 34262306a36Sopenharmony_ci data->process); 34362306a36Sopenharmony_ci} 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_cistatic int 34662306a36Sopenharmony_cikallsyms_process_symbol(void *data, const char *_name, 34762306a36Sopenharmony_ci char type __maybe_unused, u64 start) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci char disp[KSYM_NAME_LEN]; 35062306a36Sopenharmony_ci char *module, *name; 35162306a36Sopenharmony_ci unsigned long id; 35262306a36Sopenharmony_ci int err = 0; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci module = strchr(_name, '\t'); 35562306a36Sopenharmony_ci if (!module) 35662306a36Sopenharmony_ci return 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci /* We are going after [bpf] module ... */ 35962306a36Sopenharmony_ci if (strcmp(module + 1, "[bpf]")) 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci name = memdup(_name, (module - _name) + 1); 36362306a36Sopenharmony_ci if (!name) 36462306a36Sopenharmony_ci return -ENOMEM; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci name[module - _name] = 0; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci /* .. and only for trampolines and dispatchers */ 36962306a36Sopenharmony_ci if ((sscanf(name, "bpf_trampoline_%lu", &id) == 1) || 37062306a36Sopenharmony_ci (sscanf(name, "bpf_dispatcher_%s", disp) == 1)) 37162306a36Sopenharmony_ci err = process_bpf_image(name, start, data); 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci free(name); 37462306a36Sopenharmony_ci return err; 37562306a36Sopenharmony_ci} 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ciint perf_event__synthesize_bpf_events(struct perf_session *session, 37862306a36Sopenharmony_ci perf_event__handler_t process, 37962306a36Sopenharmony_ci struct machine *machine, 38062306a36Sopenharmony_ci struct record_opts *opts) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci const char *kallsyms_filename = "/proc/kallsyms"; 38362306a36Sopenharmony_ci struct kallsyms_parse arg; 38462306a36Sopenharmony_ci union perf_event *event; 38562306a36Sopenharmony_ci __u32 id = 0; 38662306a36Sopenharmony_ci int err; 38762306a36Sopenharmony_ci int fd; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci event = malloc(sizeof(event->bpf) + KSYM_NAME_LEN + machine->id_hdr_size); 39062306a36Sopenharmony_ci if (!event) 39162306a36Sopenharmony_ci return -1; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci /* Synthesize all the bpf programs in system. */ 39462306a36Sopenharmony_ci while (true) { 39562306a36Sopenharmony_ci err = bpf_prog_get_next_id(id, &id); 39662306a36Sopenharmony_ci if (err) { 39762306a36Sopenharmony_ci if (errno == ENOENT) { 39862306a36Sopenharmony_ci err = 0; 39962306a36Sopenharmony_ci break; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci pr_debug("%s: can't get next program: %s%s\n", 40262306a36Sopenharmony_ci __func__, strerror(errno), 40362306a36Sopenharmony_ci errno == EINVAL ? " -- kernel too old?" : ""); 40462306a36Sopenharmony_ci /* don't report error on old kernel or EPERM */ 40562306a36Sopenharmony_ci err = (errno == EINVAL || errno == EPERM) ? 0 : -1; 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci fd = bpf_prog_get_fd_by_id(id); 40962306a36Sopenharmony_ci if (fd < 0) { 41062306a36Sopenharmony_ci pr_debug("%s: failed to get fd for prog_id %u\n", 41162306a36Sopenharmony_ci __func__, id); 41262306a36Sopenharmony_ci continue; 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci err = perf_event__synthesize_one_bpf_prog(session, process, 41662306a36Sopenharmony_ci machine, fd, 41762306a36Sopenharmony_ci event, opts); 41862306a36Sopenharmony_ci close(fd); 41962306a36Sopenharmony_ci if (err) { 42062306a36Sopenharmony_ci /* do not return error for old kernel */ 42162306a36Sopenharmony_ci if (err == -2) 42262306a36Sopenharmony_ci err = 0; 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci /* Synthesize all the bpf images - trampolines/dispatchers. */ 42862306a36Sopenharmony_ci if (symbol_conf.kallsyms_name != NULL) 42962306a36Sopenharmony_ci kallsyms_filename = symbol_conf.kallsyms_name; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci arg = (struct kallsyms_parse) { 43262306a36Sopenharmony_ci .event = event, 43362306a36Sopenharmony_ci .process = process, 43462306a36Sopenharmony_ci .machine = machine, 43562306a36Sopenharmony_ci .tool = session->tool, 43662306a36Sopenharmony_ci }; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci if (kallsyms__parse(kallsyms_filename, &arg, kallsyms_process_symbol)) { 43962306a36Sopenharmony_ci pr_err("%s: failed to synthesize bpf images: %s\n", 44062306a36Sopenharmony_ci __func__, strerror(errno)); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci free(event); 44462306a36Sopenharmony_ci return err; 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void perf_env__add_bpf_info(struct perf_env *env, u32 id) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct bpf_prog_info_node *info_node; 45062306a36Sopenharmony_ci struct perf_bpil *info_linear; 45162306a36Sopenharmony_ci struct btf *btf = NULL; 45262306a36Sopenharmony_ci u64 arrays; 45362306a36Sopenharmony_ci u32 btf_id; 45462306a36Sopenharmony_ci int fd; 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci fd = bpf_prog_get_fd_by_id(id); 45762306a36Sopenharmony_ci if (fd < 0) 45862306a36Sopenharmony_ci return; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci arrays = 1UL << PERF_BPIL_JITED_KSYMS; 46162306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_JITED_FUNC_LENS; 46262306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_FUNC_INFO; 46362306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_PROG_TAGS; 46462306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_JITED_INSNS; 46562306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_LINE_INFO; 46662306a36Sopenharmony_ci arrays |= 1UL << PERF_BPIL_JITED_LINE_INFO; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci info_linear = get_bpf_prog_info_linear(fd, arrays); 46962306a36Sopenharmony_ci if (IS_ERR_OR_NULL(info_linear)) { 47062306a36Sopenharmony_ci pr_debug("%s: failed to get BPF program info. aborting\n", __func__); 47162306a36Sopenharmony_ci goto out; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci btf_id = info_linear->info.btf_id; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci info_node = malloc(sizeof(struct bpf_prog_info_node)); 47762306a36Sopenharmony_ci if (info_node) { 47862306a36Sopenharmony_ci info_node->info_linear = info_linear; 47962306a36Sopenharmony_ci perf_env__insert_bpf_prog_info(env, info_node); 48062306a36Sopenharmony_ci } else 48162306a36Sopenharmony_ci free(info_linear); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (btf_id == 0) 48462306a36Sopenharmony_ci goto out; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci btf = btf__load_from_kernel_by_id(btf_id); 48762306a36Sopenharmony_ci if (libbpf_get_error(btf)) { 48862306a36Sopenharmony_ci pr_debug("%s: failed to get BTF of id %u, aborting\n", 48962306a36Sopenharmony_ci __func__, btf_id); 49062306a36Sopenharmony_ci goto out; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci perf_env__fetch_btf(env, btf_id, btf); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ciout: 49562306a36Sopenharmony_ci btf__free(btf); 49662306a36Sopenharmony_ci close(fd); 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic int bpf_event__sb_cb(union perf_event *event, void *data) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci struct perf_env *env = data; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (event->header.type != PERF_RECORD_BPF_EVENT) 50462306a36Sopenharmony_ci return -1; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci switch (event->bpf.type) { 50762306a36Sopenharmony_ci case PERF_BPF_EVENT_PROG_LOAD: 50862306a36Sopenharmony_ci perf_env__add_bpf_info(env, event->bpf.id); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci case PERF_BPF_EVENT_PROG_UNLOAD: 51162306a36Sopenharmony_ci /* 51262306a36Sopenharmony_ci * Do not free bpf_prog_info and btf of the program here, 51362306a36Sopenharmony_ci * as annotation still need them. They will be freed at 51462306a36Sopenharmony_ci * the end of the session. 51562306a36Sopenharmony_ci */ 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci default: 51862306a36Sopenharmony_ci pr_debug("unexpected bpf event type of %d\n", event->bpf.type); 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci return 0; 52362306a36Sopenharmony_ci} 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ciint evlist__add_bpf_sb_event(struct evlist *evlist, struct perf_env *env) 52662306a36Sopenharmony_ci{ 52762306a36Sopenharmony_ci struct perf_event_attr attr = { 52862306a36Sopenharmony_ci .type = PERF_TYPE_SOFTWARE, 52962306a36Sopenharmony_ci .config = PERF_COUNT_SW_DUMMY, 53062306a36Sopenharmony_ci .sample_id_all = 1, 53162306a36Sopenharmony_ci .watermark = 1, 53262306a36Sopenharmony_ci .bpf_event = 1, 53362306a36Sopenharmony_ci .size = sizeof(attr), /* to capture ABI version */ 53462306a36Sopenharmony_ci }; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* 53762306a36Sopenharmony_ci * Older gcc versions don't support designated initializers, like above, 53862306a36Sopenharmony_ci * for unnamed union members, such as the following: 53962306a36Sopenharmony_ci */ 54062306a36Sopenharmony_ci attr.wakeup_watermark = 1; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return evlist__add_sb_event(evlist, &attr, bpf_event__sb_cb, env); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_civoid __bpf_event__print_bpf_prog_info(struct bpf_prog_info *info, 54662306a36Sopenharmony_ci struct perf_env *env, 54762306a36Sopenharmony_ci FILE *fp) 54862306a36Sopenharmony_ci{ 54962306a36Sopenharmony_ci __u32 *prog_lens = (__u32 *)(uintptr_t)(info->jited_func_lens); 55062306a36Sopenharmony_ci __u64 *prog_addrs = (__u64 *)(uintptr_t)(info->jited_ksyms); 55162306a36Sopenharmony_ci char name[KSYM_NAME_LEN]; 55262306a36Sopenharmony_ci struct btf *btf = NULL; 55362306a36Sopenharmony_ci u32 sub_prog_cnt, i; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci sub_prog_cnt = info->nr_jited_ksyms; 55662306a36Sopenharmony_ci if (sub_prog_cnt != info->nr_prog_tags || 55762306a36Sopenharmony_ci sub_prog_cnt != info->nr_jited_func_lens) 55862306a36Sopenharmony_ci return; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci if (info->btf_id) { 56162306a36Sopenharmony_ci struct btf_node *node; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci node = __perf_env__find_btf(env, info->btf_id); 56462306a36Sopenharmony_ci if (node) 56562306a36Sopenharmony_ci btf = btf__new((__u8 *)(node->data), 56662306a36Sopenharmony_ci node->data_size); 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (sub_prog_cnt == 1) { 57062306a36Sopenharmony_ci synthesize_bpf_prog_name(name, KSYM_NAME_LEN, info, btf, 0); 57162306a36Sopenharmony_ci fprintf(fp, "# bpf_prog_info %u: %s addr 0x%llx size %u\n", 57262306a36Sopenharmony_ci info->id, name, prog_addrs[0], prog_lens[0]); 57362306a36Sopenharmony_ci goto out; 57462306a36Sopenharmony_ci } 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci fprintf(fp, "# bpf_prog_info %u:\n", info->id); 57762306a36Sopenharmony_ci for (i = 0; i < sub_prog_cnt; i++) { 57862306a36Sopenharmony_ci synthesize_bpf_prog_name(name, KSYM_NAME_LEN, info, btf, i); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci fprintf(fp, "# \tsub_prog %u: %s addr 0x%llx size %u\n", 58162306a36Sopenharmony_ci i, name, prog_addrs[i], prog_lens[i]); 58262306a36Sopenharmony_ci } 58362306a36Sopenharmony_ciout: 58462306a36Sopenharmony_ci btf__free(btf); 58562306a36Sopenharmony_ci} 586