projects/linux·blob master · refs

572 lines · 18.1 KiB

1// SPDX-License-Identifier: GPL-2.0
2#include "data.h"
3#include "debug.h"
4#include "event.h"
5#include "header.h"
6#include "session.h"
7#include "stat.h"
8#include "tool.h"
9#include "tsc.h"
10#include <linux/compiler.h>
11#include <sys/mman.h>
12#include <stddef.h>
13#include <unistd.h>
14
15#ifdef HAVE_ZSTD_SUPPORT
16static int perf_session__process_compressed_event(const struct perf_tool *tool __maybe_unused,
17 struct perf_session *session,
18 union perf_event *event, u64 file_offset,
19 const char *file_path)
20{
21 void *src;
22 size_t decomp_size, src_size;
23 u64 decomp_last_rem = 0;
24 size_t mmap_len, decomp_len = perf_session__env(session)->comp_mmap_len;
25 struct decomp *decomp, *decomp_last = session->active_decomp->decomp_last;
26
27 if (!decomp_len) {
28 pr_err("Compressed events found but HEADER_COMPRESSED not set\n");
29 return -1;
30 }
31
32 if (decomp_last) {
33 /* Prevent u64 underflow in decomp_last_rem */
34 if (decomp_last->head > decomp_last->size)
35 return -1;
36 decomp_last_rem = decomp_last->size - decomp_last->head;
37 /*
38 * Check before adding: on 32-bit, size_t += u64
39 * silently truncates, bypassing the overflow check
40 * below and producing an undersized buffer.
41 */
42 if (decomp_last_rem > SIZE_MAX - decomp_len - sizeof(struct decomp)) {
43 pr_err("Decompression buffer size overflow\n");
44 return -1;
45 }
46 decomp_len += decomp_last_rem;
47 }
48
49 if (decomp_len > SIZE_MAX - sizeof(struct decomp)) {
50 pr_err("Decompression buffer size overflow\n");
51 return -1;
52 }
53 mmap_len = sizeof(struct decomp) + decomp_len;
54 decomp = mmap(NULL, mmap_len, PROT_READ|PROT_WRITE,
55 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
56 if (decomp == MAP_FAILED) {
57 pr_err("Couldn't allocate memory for decompression\n");
58 return -1;
59 }
60
61 decomp->file_pos = file_offset;
62 decomp->file_path = file_path;
63 decomp->mmap_len = mmap_len;
64 decomp->head = 0;
65
66 if (decomp_last_rem) {
67 memcpy(decomp->data, &(decomp_last->data[decomp_last->head]), decomp_last_rem);
68 decomp->size = decomp_last_rem;
69 }
70
71 /*
72 * Events are read directly from the mmap'd file; fields could
73 * theoretically change via a FUSE-backed file, but that applies
74 * to the entire event processing pipeline, not just here.
75 */
76 if (event->header.type == PERF_RECORD_COMPRESSED) {
77 if (event->header.size < sizeof(struct perf_record_compressed))
78 goto err_decomp;
79 src = (void *)event + sizeof(struct perf_record_compressed);
80 src_size = event->pack.header.size - sizeof(struct perf_record_compressed);
81 } else if (event->header.type == PERF_RECORD_COMPRESSED2) {
82 /*
83 * prefetch_event() only guarantees that the 8-byte
84 * event header fits; validate that header.size covers
85 * the data_size field before accessing it, otherwise a
86 * crafted event reads data_size from adjacent memory.
87 */
88 if (event->header.size < sizeof(struct perf_record_compressed2))
89 goto err_decomp;
90 src = (void *)event + sizeof(struct perf_record_compressed2);
91 src_size = event->pack2.data_size;
92 /*
93 * data_size is independent of header.size (which
94 * includes padding); verify it doesn't exceed the
95 * actual payload to prevent out-of-bounds reads in
96 * zstd_decompress_stream().
97 */
98 if (src_size > event->header.size - sizeof(struct perf_record_compressed2))
99 goto err_decomp;
100 } else {
101 goto err_decomp;
102 }
103
104 decomp_size = zstd_decompress_stream(session->active_decomp->zstd_decomp, src, src_size,
105 &(decomp->data[decomp_last_rem]), decomp_len - decomp_last_rem);
106 if (!decomp_size) {
107 munmap(decomp, mmap_len);
108 pr_err("Couldn't decompress data\n");
109 return -1;
110 }
111
112 decomp->size += decomp_size;
113
114 if (session->active_decomp->decomp == NULL)
115 session->active_decomp->decomp = decomp;
116 else
117 session->active_decomp->decomp_last->next = decomp;
118
119 session->active_decomp->decomp_last = decomp;
120
121 pr_debug("decomp (B): %zd to %zd\n", src_size, decomp_size);
122
123 return 0;
124
125err_decomp:
126 munmap(decomp, mmap_len);
127 pr_err("Couldn't decompress data\n");
128 return -1;
129}
130#endif
131
132static int process_event_synth_tracing_data_stub(const struct perf_tool *tool __maybe_unused,
133 struct perf_session *session __maybe_unused,
134 union perf_event *event __maybe_unused)
135{
136 dump_printf(": unhandled!\n");
137 return 0;
138}
139
140static int process_event_synth_attr_stub(const struct perf_tool *tool __maybe_unused,
141 union perf_event *event __maybe_unused,
142 struct evlist **pevlist __maybe_unused)
143{
144 dump_printf(": unhandled!\n");
145 return 0;
146}
147
148static int process_event_synth_event_update_stub(const struct perf_tool *tool __maybe_unused,
149 union perf_event *event __maybe_unused,
150 struct evlist **pevlist __maybe_unused)
151{
152 if (dump_trace)
153 perf_event__fprintf_event_update(event, stdout);
154
155 dump_printf(": unhandled!\n");
156 return 0;
157}
158
159int process_event_sample_stub(const struct perf_tool *tool __maybe_unused,
160 union perf_event *event __maybe_unused,
161 struct perf_sample *sample __maybe_unused,
162 struct machine *machine __maybe_unused)
163{
164 dump_printf(": unhandled!\n");
165 return 0;
166}
167
168static int process_event_stub(const struct perf_tool *tool __maybe_unused,
169 union perf_event *event __maybe_unused,
170 struct perf_sample *sample __maybe_unused,
171 struct machine *machine __maybe_unused)
172{
173 dump_printf(": unhandled!\n");
174 return 0;
175}
176
177static int process_finished_round_stub(const struct perf_tool *tool __maybe_unused,
178 union perf_event *event __maybe_unused,
179 struct ordered_events *oe __maybe_unused)
180{
181 dump_printf(": unhandled!\n");
182 return 0;
183}
184
185static int skipn(int fd, off_t n)
186{
187 char buf[4096];
188 ssize_t ret;
189
190 while (n > 0) {
191 ret = read(fd, buf, min(n, (off_t)sizeof(buf)));
192 if (ret <= 0)
193 return ret;
194 n -= ret;
195 }
196
197 return 0;
198}
199
200static s64 process_event_auxtrace_stub(const struct perf_tool *tool __maybe_unused,
201 struct perf_session *session __maybe_unused,
202 union perf_event *event)
203{
204 dump_printf(": unhandled!\n");
205 if (perf_data__is_pipe(session->data))
206 skipn(perf_data__fd(session->data), event->auxtrace.size);
207 return event->auxtrace.size;
208}
209
210static int process_event_op2_stub(const struct perf_tool *tool __maybe_unused,
211 struct perf_session *session __maybe_unused,
212 union perf_event *event __maybe_unused)
213{
214 dump_printf(": unhandled!\n");
215 return 0;
216}
217
218
219static
220int process_event_thread_map_stub(const struct perf_tool *tool __maybe_unused,
221 struct perf_session *session __maybe_unused,
222 union perf_event *event __maybe_unused)
223{
224 if (dump_trace)
225 perf_event__fprintf_thread_map(event, stdout);
226
227 dump_printf(": unhandled!\n");
228 return 0;
229}
230
231static
232int process_event_cpu_map_stub(const struct perf_tool *tool __maybe_unused,
233 struct perf_session *session __maybe_unused,
234 union perf_event *event __maybe_unused)
235{
236 if (dump_trace)
237 perf_event__fprintf_cpu_map(event, stdout);
238
239 dump_printf(": unhandled!\n");
240 return 0;
241}
242
243static
244int process_event_stat_config_stub(const struct perf_tool *tool __maybe_unused,
245 struct perf_session *session __maybe_unused,
246 union perf_event *event __maybe_unused)
247{
248 if (dump_trace)
249 perf_event__fprintf_stat_config(event, stdout);
250
251 dump_printf(": unhandled!\n");
252 return 0;
253}
254
255static int process_stat_stub(const struct perf_tool *tool __maybe_unused,
256 struct perf_session *perf_session __maybe_unused,
257 union perf_event *event)
258{
259 if (dump_trace)
260 perf_event__fprintf_stat(event, stdout);
261
262 dump_printf(": unhandled!\n");
263 return 0;
264}
265
266static int process_stat_round_stub(const struct perf_tool *tool __maybe_unused,
267 struct perf_session *perf_session __maybe_unused,
268 union perf_event *event)
269{
270 if (dump_trace)
271 perf_event__fprintf_stat_round(event, stdout);
272
273 dump_printf(": unhandled!\n");
274 return 0;
275}
276
277static int process_event_time_conv_stub(const struct perf_tool *tool __maybe_unused,
278 struct perf_session *perf_session __maybe_unused,
279 union perf_event *event)
280{
281 if (dump_trace)
282 perf_event__fprintf_time_conv(event, stdout);
283
284 dump_printf(": unhandled!\n");
285 return 0;
286}
287
288static int perf_session__process_compressed_event_stub(const struct perf_tool *tool __maybe_unused,
289 struct perf_session *session __maybe_unused,
290 union perf_event *event __maybe_unused,
291 u64 file_offset __maybe_unused,
292 const char *file_path __maybe_unused)
293{
294 dump_printf(": unhandled!\n");
295 return 0;
296}
297
298static int perf_event__process_bpf_metadata_stub(const struct perf_tool *tool __maybe_unused,
299 struct perf_session *perf_session __maybe_unused,
300 union perf_event *event)
301{
302 if (dump_trace)
303 perf_event__fprintf_bpf_metadata(event, stdout);
304 dump_printf(": unhandled!\n");
305 return 0;
306}
307static int process_schedstat_cpu_stub(const struct perf_tool *tool __maybe_unused,
308 struct perf_session *perf_session __maybe_unused,
309 union perf_event *event)
310{
311 if (dump_trace)
312 perf_event__fprintf_schedstat_cpu(event, stdout);
313 dump_printf(": unhandled!\n");
314 return 0;
315}
316
317static int process_schedstat_domain_stub(const struct perf_tool *tool __maybe_unused,
318 struct perf_session *perf_session __maybe_unused,
319 union perf_event *event)
320{
321 if (dump_trace)
322 perf_event__fprintf_schedstat_domain(event, stdout);
323 dump_printf(": unhandled!\n");
324 return 0;
325}
326
327void perf_tool__init(struct perf_tool *tool, bool ordered_events)
328{
329 tool->ordered_events = ordered_events;
330 tool->ordering_requires_timestamps = false;
331 tool->namespace_events = false;
332 tool->cgroup_events = false;
333 tool->no_warn = false;
334 tool->show_feat_hdr = SHOW_FEAT_NO_HEADER;
335 tool->merge_deferred_callchains = true;
336 tool->dont_split_sample_group = false;
337
338 tool->sample = process_event_sample_stub;
339 tool->mmap = process_event_stub;
340 tool->mmap2 = process_event_stub;
341 tool->comm = process_event_stub;
342 tool->namespaces = process_event_stub;
343 tool->cgroup = process_event_stub;
344 tool->fork = process_event_stub;
345 tool->exit = process_event_stub;
346 tool->lost = perf_event__process_lost;
347 tool->lost_samples = perf_event__process_lost_samples;
348 tool->aux = perf_event__process_aux;
349 tool->itrace_start = perf_event__process_itrace_start;
350 tool->context_switch = perf_event__process_switch;
351 tool->ksymbol = perf_event__process_ksymbol;
352 tool->bpf = perf_event__process_bpf;
353 tool->text_poke = perf_event__process_text_poke;
354 tool->aux_output_hw_id = perf_event__process_aux_output_hw_id;
355 tool->read = process_event_sample_stub;
356 tool->throttle = process_event_stub;
357 tool->unthrottle = process_event_stub;
358 tool->callchain_deferred = process_event_sample_stub;
359 tool->attr = process_event_synth_attr_stub;
360 tool->event_update = process_event_synth_event_update_stub;
361 tool->tracing_data = process_event_synth_tracing_data_stub;
362 tool->build_id = process_event_op2_stub;
363
364 if (ordered_events)
365 tool->finished_round = perf_event__process_finished_round;
366 else
367 tool->finished_round = process_finished_round_stub;
368
369 tool->id_index = process_event_op2_stub;
370 tool->auxtrace_info = process_event_op2_stub;
371 tool->auxtrace = process_event_auxtrace_stub;
372 tool->auxtrace_error = process_event_op2_stub;
373 tool->thread_map = process_event_thread_map_stub;
374 tool->cpu_map = process_event_cpu_map_stub;
375 tool->stat_config = process_event_stat_config_stub;
376 tool->stat = process_stat_stub;
377 tool->stat_round = process_stat_round_stub;
378 tool->time_conv = process_event_time_conv_stub;
379 tool->feature = process_event_op2_stub;
380#ifdef HAVE_ZSTD_SUPPORT
381 tool->compressed = perf_session__process_compressed_event;
382#else
383 tool->compressed = perf_session__process_compressed_event_stub;
384#endif
385 tool->finished_init = process_event_op2_stub;
386 tool->bpf_metadata = perf_event__process_bpf_metadata_stub;
387 tool->schedstat_cpu = process_schedstat_cpu_stub;
388 tool->schedstat_domain = process_schedstat_domain_stub;
389}
390
391bool perf_tool__compressed_is_stub(const struct perf_tool *tool)
392{
393 return tool->compressed == perf_session__process_compressed_event_stub;
394}
395
396#define CREATE_DELEGATE_SAMPLE(name) \
397 static int delegate_ ## name(const struct perf_tool *tool, \
398 union perf_event *event, \
399 struct perf_sample *sample, \
400 struct machine *machine) \
401 { \
402 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
403 struct perf_tool *delegate = del_tool->delegate; \
404 return delegate->name(delegate, event, sample, machine); \
405 }
406CREATE_DELEGATE_SAMPLE(read);
407CREATE_DELEGATE_SAMPLE(sample);
408CREATE_DELEGATE_SAMPLE(callchain_deferred);
409
410#define CREATE_DELEGATE_ATTR(name) \
411 static int delegate_ ## name(const struct perf_tool *tool, \
412 union perf_event *event, \
413 struct evlist **pevlist) \
414 { \
415 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
416 struct perf_tool *delegate = del_tool->delegate; \
417 return delegate->name(delegate, event, pevlist); \
418 }
419CREATE_DELEGATE_ATTR(attr);
420CREATE_DELEGATE_ATTR(event_update);
421
422#define CREATE_DELEGATE_OE(name) \
423 static int delegate_ ## name(const struct perf_tool *tool, \
424 union perf_event *event, \
425 struct ordered_events *oe) \
426 { \
427 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
428 struct perf_tool *delegate = del_tool->delegate; \
429 return delegate->name(delegate, event, oe); \
430 }
431CREATE_DELEGATE_OE(finished_round);
432
433#define CREATE_DELEGATE_OP(name) \
434 static int delegate_ ## name(const struct perf_tool *tool, \
435 union perf_event *event, \
436 struct perf_sample *sample, \
437 struct machine *machine) \
438 { \
439 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
440 struct perf_tool *delegate = del_tool->delegate; \
441 return delegate->name(delegate, event, sample, machine); \
442 }
443CREATE_DELEGATE_OP(aux);
444CREATE_DELEGATE_OP(aux_output_hw_id);
445CREATE_DELEGATE_OP(bpf);
446CREATE_DELEGATE_OP(cgroup);
447CREATE_DELEGATE_OP(comm);
448CREATE_DELEGATE_OP(context_switch);
449CREATE_DELEGATE_OP(exit);
450CREATE_DELEGATE_OP(fork);
451CREATE_DELEGATE_OP(itrace_start);
452CREATE_DELEGATE_OP(ksymbol);
453CREATE_DELEGATE_OP(lost);
454CREATE_DELEGATE_OP(lost_samples);
455CREATE_DELEGATE_OP(mmap);
456CREATE_DELEGATE_OP(mmap2);
457CREATE_DELEGATE_OP(namespaces);
458CREATE_DELEGATE_OP(text_poke);
459CREATE_DELEGATE_OP(throttle);
460CREATE_DELEGATE_OP(unthrottle);
461
462#define CREATE_DELEGATE_OP2(name) \
463 static int delegate_ ## name(const struct perf_tool *tool, \
464 struct perf_session *session, \
465 union perf_event *event) \
466 { \
467 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
468 struct perf_tool *delegate = del_tool->delegate; \
469 return delegate->name(delegate, session, event); \
470 }
471CREATE_DELEGATE_OP2(auxtrace_error);
472CREATE_DELEGATE_OP2(auxtrace_info);
473CREATE_DELEGATE_OP2(bpf_metadata);
474CREATE_DELEGATE_OP2(build_id);
475CREATE_DELEGATE_OP2(cpu_map);
476CREATE_DELEGATE_OP2(feature);
477CREATE_DELEGATE_OP2(finished_init);
478CREATE_DELEGATE_OP2(id_index);
479CREATE_DELEGATE_OP2(stat);
480CREATE_DELEGATE_OP2(stat_config);
481CREATE_DELEGATE_OP2(stat_round);
482CREATE_DELEGATE_OP2(thread_map);
483CREATE_DELEGATE_OP2(time_conv);
484CREATE_DELEGATE_OP2(schedstat_cpu);
485CREATE_DELEGATE_OP2(schedstat_domain);
486CREATE_DELEGATE_OP2(tracing_data);
487
488#define CREATE_DELEGATE_OP3(name) \
489 static s64 delegate_ ## name(const struct perf_tool *tool, \
490 struct perf_session *session, \
491 union perf_event *event) \
492 { \
493 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
494 struct perf_tool *delegate = del_tool->delegate; \
495 return delegate->name(delegate, session, event); \
496 }
497CREATE_DELEGATE_OP3(auxtrace);
498
499#define CREATE_DELEGATE_OP4(name) \
500 static int delegate_ ## name(const struct perf_tool *tool, \
501 struct perf_session *session, \
502 union perf_event *event, \
503 u64 data, \
504 const char *str) \
505 { \
506 struct delegate_tool *del_tool = container_of(tool, struct delegate_tool, tool); \
507 struct perf_tool *delegate = del_tool->delegate; \
508 return delegate->name(delegate, session, event, data, str); \
509 }
510CREATE_DELEGATE_OP4(compressed);
511
512void delegate_tool__init(struct delegate_tool *tool, struct perf_tool *delegate)
513{
514 tool->delegate = delegate;
515
516 tool->tool.ordered_events = delegate->ordered_events;
517 tool->tool.ordering_requires_timestamps = delegate->ordering_requires_timestamps;
518 tool->tool.namespace_events = delegate->namespace_events;
519 tool->tool.cgroup_events = delegate->cgroup_events;
520 tool->tool.no_warn = delegate->no_warn;
521 tool->tool.show_feat_hdr = delegate->show_feat_hdr;
522 tool->tool.merge_deferred_callchains = delegate->merge_deferred_callchains;
523 tool->tool.dont_split_sample_group = delegate->dont_split_sample_group;
524
525 tool->tool.sample = delegate_sample;
526 tool->tool.read = delegate_read;
527
528 tool->tool.mmap = delegate_mmap;
529 tool->tool.mmap2 = delegate_mmap2;
530 tool->tool.comm = delegate_comm;
531 tool->tool.namespaces = delegate_namespaces;
532 tool->tool.cgroup = delegate_cgroup;
533 tool->tool.fork = delegate_fork;
534 tool->tool.exit = delegate_exit;
535 tool->tool.lost = delegate_lost;
536 tool->tool.lost_samples = delegate_lost_samples;
537 tool->tool.aux = delegate_aux;
538 tool->tool.itrace_start = delegate_itrace_start;
539 tool->tool.aux_output_hw_id = delegate_aux_output_hw_id;
540 tool->tool.context_switch = delegate_context_switch;
541 tool->tool.throttle = delegate_throttle;
542 tool->tool.unthrottle = delegate_unthrottle;
543 tool->tool.ksymbol = delegate_ksymbol;
544 tool->tool.bpf = delegate_bpf;
545 tool->tool.text_poke = delegate_text_poke;
546 tool->tool.callchain_deferred = delegate_callchain_deferred;
547
548 tool->tool.attr = delegate_attr;
549 tool->tool.event_update = delegate_event_update;
550
551 tool->tool.tracing_data = delegate_tracing_data;
552
553 tool->tool.finished_round = delegate_finished_round;
554
555 tool->tool.build_id = delegate_build_id;
556 tool->tool.id_index = delegate_id_index;
557 tool->tool.auxtrace_info = delegate_auxtrace_info;
558 tool->tool.auxtrace_error = delegate_auxtrace_error;
559 tool->tool.time_conv = delegate_time_conv;
560 tool->tool.thread_map = delegate_thread_map;
561 tool->tool.cpu_map = delegate_cpu_map;
562 tool->tool.stat_config = delegate_stat_config;
563 tool->tool.stat = delegate_stat;
564 tool->tool.stat_round = delegate_stat_round;
565 tool->tool.feature = delegate_feature;
566 tool->tool.finished_init = delegate_finished_init;
567 tool->tool.bpf_metadata = delegate_bpf_metadata;
568 tool->tool.compressed = delegate_compressed;
569 tool->tool.auxtrace = delegate_auxtrace;
570 tool->tool.schedstat_cpu = delegate_schedstat_cpu;
571 tool->tool.schedstat_domain = delegate_schedstat_domain;
572}