xref: /linux/tools/perf/util/tool.c (revision d88e954c8271c9c47d6d50dcfdd864e6b031d166)
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
16 static 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 
125 err_decomp:
126 	munmap(decomp, mmap_len);
127 	pr_err("Couldn't decompress data\n");
128 	return -1;
129 }
130 #endif
131 
132 static 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 
140 static 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 
148 static 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 
159 int 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 
168 static 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 
177 static 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 
185 static 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 
200 static 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 
210 static 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 
219 static
220 int 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 
231 static
232 int 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 
243 static
244 int 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 
255 static 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 
266 static 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 
277 static 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 
288 static 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 
298 static 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 }
307 static 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 
317 static 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 
327 void 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 
391 bool 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 	}
406 CREATE_DELEGATE_SAMPLE(read);
407 CREATE_DELEGATE_SAMPLE(sample);
408 CREATE_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 	}
419 CREATE_DELEGATE_ATTR(attr);
420 CREATE_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 	}
431 CREATE_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 	}
443 CREATE_DELEGATE_OP(aux);
444 CREATE_DELEGATE_OP(aux_output_hw_id);
445 CREATE_DELEGATE_OP(bpf);
446 CREATE_DELEGATE_OP(cgroup);
447 CREATE_DELEGATE_OP(comm);
448 CREATE_DELEGATE_OP(context_switch);
449 CREATE_DELEGATE_OP(exit);
450 CREATE_DELEGATE_OP(fork);
451 CREATE_DELEGATE_OP(itrace_start);
452 CREATE_DELEGATE_OP(ksymbol);
453 CREATE_DELEGATE_OP(lost);
454 CREATE_DELEGATE_OP(lost_samples);
455 CREATE_DELEGATE_OP(mmap);
456 CREATE_DELEGATE_OP(mmap2);
457 CREATE_DELEGATE_OP(namespaces);
458 CREATE_DELEGATE_OP(text_poke);
459 CREATE_DELEGATE_OP(throttle);
460 CREATE_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 	}
471 CREATE_DELEGATE_OP2(auxtrace_error);
472 CREATE_DELEGATE_OP2(auxtrace_info);
473 CREATE_DELEGATE_OP2(bpf_metadata);
474 CREATE_DELEGATE_OP2(build_id);
475 CREATE_DELEGATE_OP2(cpu_map);
476 CREATE_DELEGATE_OP2(feature);
477 CREATE_DELEGATE_OP2(finished_init);
478 CREATE_DELEGATE_OP2(id_index);
479 CREATE_DELEGATE_OP2(stat);
480 CREATE_DELEGATE_OP2(stat_config);
481 CREATE_DELEGATE_OP2(stat_round);
482 CREATE_DELEGATE_OP2(thread_map);
483 CREATE_DELEGATE_OP2(time_conv);
484 CREATE_DELEGATE_OP2(schedstat_cpu);
485 CREATE_DELEGATE_OP2(schedstat_domain);
486 CREATE_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 	}
497 CREATE_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 	}
510 CREATE_DELEGATE_OP4(compressed);
511 
512 void 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 }
573