// SPDX-License-Identifier: GPL-2.0
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <bpf/bpf.h>
#include <bpf/btf.h>
#include <bpf/libbpf.h>
#include <linux/bpf.h>
#include <linux/btf.h>
#include <linux/err.h>
#include <linux/perf_event.h>
#include <linux/string.h>
#include <linux/zalloc.h>
#include <internal/lib.h>
#include <perf/event.h>
#include <symbol/kallsyms.h>
#include "bpf-event.h"
#include "bpf-utils.h"
#include "debug.h"
#include "dso.h"
#include "symbol.h"
#include "machine.h"
#include "env.h"
#include "session.h"
#include "map.h"
#include "evlist.h"
#include "record.h"
#include "util/synthetic-events.h"
static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
{
int ret = 0;
size_t i;
for (i = 0; i < len; i++)
ret += snprintf(buf + ret, size - ret, "%02x", data[i]);
return ret;
}
static int machine__process_bpf_event_load(struct machine *machine,
union perf_event *event,
struct perf_sample *sample __maybe_unused)
{
struct bpf_prog_info_node *info_node;
struct perf_env *env = machine->env;
struct perf_bpil *info_linear;
int id = event->bpf.id;
unsigned int i;
/* perf-record, no need to handle bpf-event */
if (env == NULL)
return 0;
info_node = perf_env__find_bpf_prog_info(env, id);
if (!info_node)
return 0;
info_linear = info_node->info_linear;
for (i = 0; i < info_linear->info.nr_jited_ksyms; i++) {
u64 *addrs = (u64 *)(uintptr_t)(info_linear->info.jited_ksyms);
u64 addr = addrs[i];
struct map *map = maps__find(machine__kernel_maps(machine), addr);
if (map) {
struct dso *dso = map__dso(map);
dso__set_binary_type(dso, DSO_BINARY_TYPE__BPF_PROG_INFO);
dso__bpf_prog(dso)->id = id;
dso__bpf_prog(dso)->sub_id = i;
dso__bpf_prog(dso)->env = env;
map__put(map);
}
}
return 0;
}
int machine__process_bpf(struct machine *machine, union perf_event *event,
struct perf_sample *sample)
{
if (dump_trace)
perf_event__fprintf_bpf(event, stdout);
switch (event->bpf.type) {
case PERF_BPF_EVENT_PROG_LOAD:
return machine__process_bpf_event_load(machine, event, sample);
case PERF_BPF_EVENT_PROG_UNLOAD:
/*
* Do not free bpf_prog_info and btf of the program here,
* as annotation still need them. They will be freed at
* the end of the session.
*/
break;
default:
pr_debug("unexpected bpf event type of %d\n", event->bpf.type);
break;
}
return 0;
}
static int perf_env__fetch_btf(struct perf_env *env,
u32 btf_id,
struct btf *btf)
{
struct btf_node *node;
u32 data_size;
const void *data;
data = btf__raw_data(btf, &data_size);
node = malloc(data_size + sizeof(struct btf_node));
if (!node)
return -1;
node->id = btf_id;
node->data_size = data_size;
memcpy(node->data, data, data_size);
if (!perf_env__insert_btf(env, node)) {
/* Insertion failed because of a duplicate. */
free(node);
return -1;
}
return 0;
}
static int synthesize_bpf_prog_name(char *buf, int size,
struct bpf_prog_info *info,
struct btf *btf,
u32 sub_id)
{
u8 (*prog_tags)[BPF_TAG_SIZE] = (void *)(uintptr_t)(info->prog_tags);
void *func_infos = (void *)(uintptr_t)(info->