162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (c) 2020 Facebook */
362306a36Sopenharmony_ci#include <vmlinux.h>
462306a36Sopenharmony_ci#include <bpf/bpf_helpers.h>
562306a36Sopenharmony_ci#include <bpf/bpf_core_read.h>
662306a36Sopenharmony_ci#include <bpf/bpf_tracing.h>
762306a36Sopenharmony_ci#include "pid_iter.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/* keep in sync with the definition in main.h */
1062306a36Sopenharmony_cienum bpf_obj_type {
1162306a36Sopenharmony_ci	BPF_OBJ_UNKNOWN,
1262306a36Sopenharmony_ci	BPF_OBJ_PROG,
1362306a36Sopenharmony_ci	BPF_OBJ_MAP,
1462306a36Sopenharmony_ci	BPF_OBJ_LINK,
1562306a36Sopenharmony_ci	BPF_OBJ_BTF,
1662306a36Sopenharmony_ci};
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistruct bpf_perf_link___local {
1962306a36Sopenharmony_ci	struct bpf_link link;
2062306a36Sopenharmony_ci	struct file *perf_file;
2162306a36Sopenharmony_ci} __attribute__((preserve_access_index));
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct perf_event___local {
2462306a36Sopenharmony_ci	u64 bpf_cookie;
2562306a36Sopenharmony_ci} __attribute__((preserve_access_index));
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cienum bpf_link_type___local {
2862306a36Sopenharmony_ci	BPF_LINK_TYPE_PERF_EVENT___local = 7,
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ciextern const void bpf_link_fops __ksym;
3262306a36Sopenharmony_ciextern const void bpf_map_fops __ksym;
3362306a36Sopenharmony_ciextern const void bpf_prog_fops __ksym;
3462306a36Sopenharmony_ciextern const void btf_fops __ksym;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ciconst volatile enum bpf_obj_type obj_type = BPF_OBJ_UNKNOWN;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	switch (type) {
4162306a36Sopenharmony_ci	case BPF_OBJ_PROG:
4262306a36Sopenharmony_ci		return BPF_CORE_READ((struct bpf_prog *)ent, aux, id);
4362306a36Sopenharmony_ci	case BPF_OBJ_MAP:
4462306a36Sopenharmony_ci		return BPF_CORE_READ((struct bpf_map *)ent, id);
4562306a36Sopenharmony_ci	case BPF_OBJ_BTF:
4662306a36Sopenharmony_ci		return BPF_CORE_READ((struct btf *)ent, id);
4762306a36Sopenharmony_ci	case BPF_OBJ_LINK:
4862306a36Sopenharmony_ci		return BPF_CORE_READ((struct bpf_link *)ent, id);
4962306a36Sopenharmony_ci	default:
5062306a36Sopenharmony_ci		return 0;
5162306a36Sopenharmony_ci	}
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci/* could be used only with BPF_LINK_TYPE_PERF_EVENT links */
5562306a36Sopenharmony_cistatic __u64 get_bpf_cookie(struct bpf_link *link)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	struct bpf_perf_link___local *perf_link;
5862306a36Sopenharmony_ci	struct perf_event___local *event;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	perf_link = container_of(link, struct bpf_perf_link___local, link);
6162306a36Sopenharmony_ci	event = BPF_CORE_READ(perf_link, perf_file, private_data);
6262306a36Sopenharmony_ci	return BPF_CORE_READ(event, bpf_cookie);
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ciSEC("iter/task_file")
6662306a36Sopenharmony_ciint iter(struct bpf_iter__task_file *ctx)
6762306a36Sopenharmony_ci{
6862306a36Sopenharmony_ci	struct file *file = ctx->file;
6962306a36Sopenharmony_ci	struct task_struct *task = ctx->task;
7062306a36Sopenharmony_ci	struct pid_iter_entry e;
7162306a36Sopenharmony_ci	const void *fops;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	if (!file || !task)
7462306a36Sopenharmony_ci		return 0;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	switch (obj_type) {
7762306a36Sopenharmony_ci	case BPF_OBJ_PROG:
7862306a36Sopenharmony_ci		fops = &bpf_prog_fops;
7962306a36Sopenharmony_ci		break;
8062306a36Sopenharmony_ci	case BPF_OBJ_MAP:
8162306a36Sopenharmony_ci		fops = &bpf_map_fops;
8262306a36Sopenharmony_ci		break;
8362306a36Sopenharmony_ci	case BPF_OBJ_BTF:
8462306a36Sopenharmony_ci		fops = &btf_fops;
8562306a36Sopenharmony_ci		break;
8662306a36Sopenharmony_ci	case BPF_OBJ_LINK:
8762306a36Sopenharmony_ci		fops = &bpf_link_fops;
8862306a36Sopenharmony_ci		break;
8962306a36Sopenharmony_ci	default:
9062306a36Sopenharmony_ci		return 0;
9162306a36Sopenharmony_ci	}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci	if (file->f_op != fops)
9462306a36Sopenharmony_ci		return 0;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	__builtin_memset(&e, 0, sizeof(e));
9762306a36Sopenharmony_ci	e.pid = task->tgid;
9862306a36Sopenharmony_ci	e.id = get_obj_id(file->private_data, obj_type);
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	if (obj_type == BPF_OBJ_LINK &&
10162306a36Sopenharmony_ci	    bpf_core_enum_value_exists(enum bpf_link_type___local,
10262306a36Sopenharmony_ci				       BPF_LINK_TYPE_PERF_EVENT___local)) {
10362306a36Sopenharmony_ci		struct bpf_link *link = (struct bpf_link *) file->private_data;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		if (link->type == bpf_core_enum_value(enum bpf_link_type___local,
10662306a36Sopenharmony_ci						      BPF_LINK_TYPE_PERF_EVENT___local)) {
10762306a36Sopenharmony_ci			e.has_bpf_cookie = true;
10862306a36Sopenharmony_ci			e.bpf_cookie = get_bpf_cookie(link);
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	bpf_probe_read_kernel_str(&e.comm, sizeof(e.comm),
11362306a36Sopenharmony_ci				  task->group_leader->comm);
11462306a36Sopenharmony_ci	bpf_seq_write(ctx->meta->seq, &e, sizeof(e));
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cichar LICENSE[] SEC("license") = "Dual BSD/GPL";
120