1 // SPDX-License-Identifier: GPL-2.0
12 #define ptr_to_u64(ptr) ((__u64)(unsigned long)(ptr))
14 static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)
19 for (i = 0; i < len; i++)
20 ret += snprintf(buf + ret, size - ret, "%02x", data[i]);
24 int machine__process_bpf_event(struct machine *machine __maybe_unused,
25 union perf_event *event,
26 struct perf_sample *sample __maybe_unused)
29 perf_event__fprintf_bpf_event(event, stdout);
34 * Synthesize PERF_RECORD_KSYMBOL and PERF_RECORD_BPF_EVENT for one bpf
35 * program. One PERF_RECORD_BPF_EVENT is generated for the program. And
36 * one PERF_RECORD_KSYMBOL is generated for each sub program.
41 * -2 for lack of kernel support.
43 static int perf_event__synthesize_one_bpf_prog(struct perf_tool *tool,
44 perf_event__handler_t process,
45 struct machine *machine,
47 union perf_event *event,
48 struct record_opts *opts)
50 struct ksymbol_event *ksymbol_event = &event->ksymbol_event;
51 struct bpf_event *bpf_event = &event->bpf_event;
52 u32 sub_prog_cnt, i, func_info_rec_size = 0;
53 u8 (*prog_tags)[BPF_TAG_SIZE] = NULL;
54 struct bpf_prog_info info = { .type = 0, };
55 u32 info_len = sizeof(info);
56 void *func_infos = NULL;
57 u64 *prog_addrs = NULL;
58 struct btf *btf = NULL;
59 u32 *prog_lens = NULL;
64 /* Call bpf_obj_get_info_by_fd() to get sizes of arrays */
65 err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
68 pr_debug("%s: failed to get BPF program info: %s, aborting\n",
69 __func__, str_error_r(errno, errbuf, sizeof(errbuf)));
72 if (info_len < offsetof(struct bpf_prog_info, prog_tags)) {
73 pr_debug("%s: the kernel is too old, aborting\n", __func__);
77 /* number of ksyms, func_lengths, and tags should match */
78 sub_prog_cnt = info.nr_jited_ksyms;
79 if (sub_prog_cnt != info.nr_prog_tags ||
80 sub_prog_cnt != info.nr_jited_func_lens)
83 /* check BTF func info support */
84 if (info.btf_id && info.nr_func_info && info.func_info_rec_size) {
85 /* btf func info number should be same as sub_prog_cnt */
86 if (sub_prog_cnt != info.nr_func_info) {
87 pr_debug("%s: mismatch in BPF sub program count and BTF function info count, aborting\n", __func__);
90 if (btf__get_from_id(info.btf_id, &btf)) {
91 pr_debug("%s: failed to get BTF of id %u, aborting\n", __func__, info.btf_id);
94 func_info_rec_size = info.func_info_rec_size;
95 func_infos = calloc(sub_prog_cnt, func_info_rec_size);
97 pr_debug("%s: failed to allocate memory for func_infos, aborting\n", __func__);
104 * We need address, length, and tag for each sub program.
105 * Allocate memory and call bpf_obj_get_info_by_fd() again
107 prog_addrs = calloc(sub_prog_cnt, sizeof(u64));
109 pr_debug("%s: failed to allocate memory for prog_addrs, aborting\n", __func__);
112 prog_lens = calloc(sub_prog_cnt, sizeof(u32));
114 pr_debug("%s: failed to allocate memory for prog_lens, aborting\n", __func__);
117 prog_tags = calloc(sub_prog_cnt, BPF_TAG_SIZE);
119 pr_debug("%s: failed to allocate memory for prog_tags, aborting\n", __func__);
123 memset(&info, 0, sizeof(info));
124 info.nr_jited_ksyms = sub_prog_cnt;
125 info.nr_jited_func_lens = sub_prog_cnt;
126 info.nr_prog_tags = sub_prog_cnt;
127 info.jited_ksyms = ptr_to_u64(prog_addrs);
128 info.jited_func_lens = ptr_to_u64(prog_lens);
129 info.prog_tags = ptr_to_u64(prog_tags);
130 info_len = sizeof(info);
132 info.nr_func_info = sub_prog_cnt;
133 info.func_info_rec_size = func_info_rec_size;
134 info.func_info = ptr_to_u64(func_infos);
137 err = bpf_obj_get_info_by_fd(fd, &info, &info_len);
139 pr_debug("%s: failed to get BPF program info, aborting\n", __func__);
143 /* Synthesize PERF_RECORD_KSYMBOL */
144 for (i = 0; i < sub_prog_cnt; i++) {
145 const struct bpf_func_info *finfo;
146 const char *short_name = NULL;
147 const struct btf_type *t;
150 *ksymbol_event = (struct ksymbol_event){
152 .type = PERF_RECORD_KSYMBOL,
153 .size = offsetof(struct ksymbol_event, name),
155 .addr = prog_addrs[i],
157 .ksym_type = PERF_RECORD_KSYMBOL_TYPE_BPF,
160 name_len = snprintf(ksymbol_event->name, KSYM_NAME_LEN,
162 name_len += snprintf_hex(ksymbol_event->name + name_len,
163 KSYM_NAME_LEN - name_len,
164 prog_tags[i], BPF_TAG_SIZE);
166 finfo = func_infos + i * info.func_info_rec_size;
167 t = btf__type_by_id(btf, finfo->type_id);
168 short_name = btf__name_by_offset(btf, t->name_off);
169 } else if (i == 0 && sub_prog_cnt == 1) {
172 short_name = info.name;
176 name_len += snprintf(ksymbol_event->name + name_len,
177 KSYM_NAME_LEN - name_len,
180 ksymbol_event->header.size += PERF_ALIGN(name_len + 1,
183 memset((void *)event + event->header.size, 0, machine->id_hdr_size);
184 event->header.size += machine->id_hdr_size;
185 err = perf_tool__process_synth_event(tool, event,
189 /* Synthesize PERF_RECORD_BPF_EVENT */
190 if (opts->bpf_event) {
191 *bpf_event = (struct bpf_event){
193 .type = PERF_RECORD_BPF_EVENT,
194 .size = sizeof(struct bpf_event),
196 .type = PERF_BPF_EVENT_PROG_LOAD,
200 memcpy(bpf_event->tag, prog_tags[i], BPF_TAG_SIZE);
201 memset((void *)event + event->header.size, 0, machine->id_hdr_size);
202 event->header.size += machine->id_hdr_size;
203 err = perf_tool__process_synth_event(tool, event,
216 int perf_event__synthesize_bpf_events(struct perf_tool *tool,
217 perf_event__handler_t process,
218 struct machine *machine,
219 struct record_opts *opts)
221 union perf_event *event;
226 event = malloc(sizeof(event->bpf_event) + KSYM_NAME_LEN + machine->id_hdr_size);
230 err = bpf_prog_get_next_id(id, &id);
232 if (errno == ENOENT) {
236 pr_debug("%s: can't get next program: %s%s\n",
237 __func__, strerror(errno),
238 errno == EINVAL ? " -- kernel too old?" : "");
239 /* don't report error on old kernel or EPERM */
240 err = (errno == EINVAL || errno == EPERM) ? 0 : -1;
243 fd = bpf_prog_get_fd_by_id(id);
245 pr_debug("%s: failed to get fd for prog_id %u\n",
250 err = perf_event__synthesize_one_bpf_prog(tool, process,
255 /* do not return error for old kernel */