1d53dee3fSAndrii Nakryiko // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2d53dee3fSAndrii Nakryiko /* Copyright (c) 2020 Facebook */
3d53dee3fSAndrii Nakryiko #include <vmlinux.h>
4d53dee3fSAndrii Nakryiko #include <bpf/bpf_helpers.h>
5d53dee3fSAndrii Nakryiko #include <bpf/bpf_core_read.h>
6d53dee3fSAndrii Nakryiko #include <bpf/bpf_tracing.h>
7d53dee3fSAndrii Nakryiko #include "pid_iter.h"
8d53dee3fSAndrii Nakryiko 
9d53dee3fSAndrii Nakryiko /* keep in sync with the definition in main.h */
10d53dee3fSAndrii Nakryiko enum bpf_obj_type {
11d53dee3fSAndrii Nakryiko 	BPF_OBJ_UNKNOWN,
12d53dee3fSAndrii Nakryiko 	BPF_OBJ_PROG,
13d53dee3fSAndrii Nakryiko 	BPF_OBJ_MAP,
14d53dee3fSAndrii Nakryiko 	BPF_OBJ_LINK,
15d53dee3fSAndrii Nakryiko 	BPF_OBJ_BTF,
16d53dee3fSAndrii Nakryiko };
17d53dee3fSAndrii Nakryiko 
1867a43462SAlexander Lobakin struct bpf_perf_link___local {
1967a43462SAlexander Lobakin 	struct bpf_link link;
2067a43462SAlexander Lobakin 	struct file *perf_file;
2167a43462SAlexander Lobakin } __attribute__((preserve_access_index));
2267a43462SAlexander Lobakin 
234cbeeb0dSAlexander Lobakin struct perf_event___local {
244cbeeb0dSAlexander Lobakin 	u64 bpf_cookie;
254cbeeb0dSAlexander Lobakin } __attribute__((preserve_access_index));
264cbeeb0dSAlexander Lobakin 
2744ba7b30SQuentin Monnet enum bpf_link_type___local {
2844ba7b30SQuentin Monnet 	BPF_LINK_TYPE_PERF_EVENT___local = 7,
2944ba7b30SQuentin Monnet };
3044ba7b30SQuentin Monnet 
31d53dee3fSAndrii Nakryiko extern const void bpf_link_fops __ksym;
32d53dee3fSAndrii Nakryiko extern const void bpf_map_fops __ksym;
33d53dee3fSAndrii Nakryiko extern const void bpf_prog_fops __ksym;
34d53dee3fSAndrii Nakryiko extern const void btf_fops __ksym;
35d53dee3fSAndrii Nakryiko 
36d53dee3fSAndrii Nakryiko const volatile enum bpf_obj_type obj_type = BPF_OBJ_UNKNOWN;
37d53dee3fSAndrii Nakryiko 
get_obj_id(void * ent,enum bpf_obj_type type)38d53dee3fSAndrii Nakryiko static __always_inline __u32 get_obj_id(void *ent, enum bpf_obj_type type)
39d53dee3fSAndrii Nakryiko {
40d53dee3fSAndrii Nakryiko 	switch (type) {
41d53dee3fSAndrii Nakryiko 	case BPF_OBJ_PROG:
42d53dee3fSAndrii Nakryiko 		return BPF_CORE_READ((struct bpf_prog *)ent, aux, id);
43d53dee3fSAndrii Nakryiko 	case BPF_OBJ_MAP:
44d53dee3fSAndrii Nakryiko 		return BPF_CORE_READ((struct bpf_map *)ent, id);
45d53dee3fSAndrii Nakryiko 	case BPF_OBJ_BTF:
46d53dee3fSAndrii Nakryiko 		return BPF_CORE_READ((struct btf *)ent, id);
47d53dee3fSAndrii Nakryiko 	case BPF_OBJ_LINK:
48d53dee3fSAndrii Nakryiko 		return BPF_CORE_READ((struct bpf_link *)ent, id);
49d53dee3fSAndrii Nakryiko 	default:
50d53dee3fSAndrii Nakryiko 		return 0;
51d53dee3fSAndrii Nakryiko 	}
52d53dee3fSAndrii Nakryiko }
53d53dee3fSAndrii Nakryiko 
54cbdaf71fSDmitrii Dolgov /* could be used only with BPF_LINK_TYPE_PERF_EVENT links */
get_bpf_cookie(struct bpf_link * link)55cbdaf71fSDmitrii Dolgov static __u64 get_bpf_cookie(struct bpf_link *link)
56cbdaf71fSDmitrii Dolgov {
5767a43462SAlexander Lobakin 	struct bpf_perf_link___local *perf_link;
584cbeeb0dSAlexander Lobakin 	struct perf_event___local *event;
59cbdaf71fSDmitrii Dolgov 
6067a43462SAlexander Lobakin 	perf_link = container_of(link, struct bpf_perf_link___local, link);
61cbdaf71fSDmitrii Dolgov 	event = BPF_CORE_READ(perf_link, perf_file, private_data);
62cbdaf71fSDmitrii Dolgov 	return BPF_CORE_READ(event, bpf_cookie);
63cbdaf71fSDmitrii Dolgov }
64cbdaf71fSDmitrii Dolgov 
65d53dee3fSAndrii Nakryiko SEC("iter/task_file")
iter(struct bpf_iter__task_file * ctx)66d53dee3fSAndrii Nakryiko int iter(struct bpf_iter__task_file *ctx)
67d53dee3fSAndrii Nakryiko {
68d53dee3fSAndrii Nakryiko 	struct file *file = ctx->file;
69d53dee3fSAndrii Nakryiko 	struct task_struct *task = ctx->task;
70d53dee3fSAndrii Nakryiko 	struct pid_iter_entry e;
71d53dee3fSAndrii Nakryiko 	const void *fops;
72d53dee3fSAndrii Nakryiko 
73d53dee3fSAndrii Nakryiko 	if (!file || !task)
74d53dee3fSAndrii Nakryiko 		return 0;
75d53dee3fSAndrii Nakryiko 
76d53dee3fSAndrii Nakryiko 	switch (obj_type) {
77d53dee3fSAndrii Nakryiko 	case BPF_OBJ_PROG:
78d53dee3fSAndrii Nakryiko 		fops = &bpf_prog_fops;
79d53dee3fSAndrii Nakryiko 		break;
80d53dee3fSAndrii Nakryiko 	case BPF_OBJ_MAP:
81d53dee3fSAndrii Nakryiko 		fops = &bpf_map_fops;
82d53dee3fSAndrii Nakryiko 		break;
83d53dee3fSAndrii Nakryiko 	case BPF_OBJ_BTF:
84d53dee3fSAndrii Nakryiko 		fops = &btf_fops;
85d53dee3fSAndrii Nakryiko 		break;
86d53dee3fSAndrii Nakryiko 	case BPF_OBJ_LINK:
87d53dee3fSAndrii Nakryiko 		fops = &bpf_link_fops;
88d53dee3fSAndrii Nakryiko 		break;
89d53dee3fSAndrii Nakryiko 	default:
90d53dee3fSAndrii Nakryiko 		return 0;
91d53dee3fSAndrii Nakryiko 	}
92d53dee3fSAndrii Nakryiko 
93d53dee3fSAndrii Nakryiko 	if (file->f_op != fops)
94d53dee3fSAndrii Nakryiko 		return 0;
95d53dee3fSAndrii Nakryiko 
96cbdaf71fSDmitrii Dolgov 	__builtin_memset(&e, 0, sizeof(e));
97d53dee3fSAndrii Nakryiko 	e.pid = task->tgid;
98d53dee3fSAndrii Nakryiko 	e.id = get_obj_id(file->private_data, obj_type);
99cbdaf71fSDmitrii Dolgov 
10044ba7b30SQuentin Monnet 	if (obj_type == BPF_OBJ_LINK &&
10144ba7b30SQuentin Monnet 	    bpf_core_enum_value_exists(enum bpf_link_type___local,
10244ba7b30SQuentin Monnet 				       BPF_LINK_TYPE_PERF_EVENT___local)) {
103cbdaf71fSDmitrii Dolgov 		struct bpf_link *link = (struct bpf_link *) file->private_data;
104cbdaf71fSDmitrii Dolgov 
105ba3647aaSYonghong Song 		if (BPF_CORE_READ(link, type) == bpf_core_enum_value(enum bpf_link_type___local,
10644ba7b30SQuentin Monnet 								     BPF_LINK_TYPE_PERF_EVENT___local)) {
107cbdaf71fSDmitrii Dolgov 			e.has_bpf_cookie = true;
108cbdaf71fSDmitrii Dolgov 			e.bpf_cookie = get_bpf_cookie(link);
109cbdaf71fSDmitrii Dolgov 		}
110cbdaf71fSDmitrii Dolgov 	}
111cbdaf71fSDmitrii Dolgov 
1124cfb9435SYafang Shao 	bpf_probe_read_kernel_str(&e.comm, sizeof(e.comm),
113e4d9c232SIlya Leoshkevich 				  task->group_leader->comm);
114d53dee3fSAndrii Nakryiko 	bpf_seq_write(ctx->meta->seq, &e, sizeof(e));
115d53dee3fSAndrii Nakryiko 
116d53dee3fSAndrii Nakryiko 	return 0;
117d53dee3fSAndrii Nakryiko }
118d53dee3fSAndrii Nakryiko 
119d53dee3fSAndrii Nakryiko char LICENSE[] SEC("license") = "Dual BSD/GPL";
120