xref: /linux/tools/perf/builtin-inject.c (revision 607bfbd7ffc60156ae0831c917497dc91a57dd8d)
1 /*
2  * builtin-inject.c
3  *
4  * Builtin inject command: Examine the live mode (stdin) event stream
5  * and repipe it to stdout while optionally injecting additional
6  * events into it.
7  */
8 #include "builtin.h"
9 
10 #include "perf.h"
11 #include "util/color.h"
12 #include "util/evlist.h"
13 #include "util/evsel.h"
14 #include "util/session.h"
15 #include "util/tool.h"
16 #include "util/debug.h"
17 #include "util/build-id.h"
18 #include "util/data.h"
19 #include "util/auxtrace.h"
20 #include "util/jit.h"
21 
22 #include <subcmd/parse-options.h>
23 
24 #include <linux/list.h>
25 
26 struct perf_inject {
27 	struct perf_tool	tool;
28 	struct perf_session	*session;
29 	bool			build_ids;
30 	bool			sched_stat;
31 	bool			have_auxtrace;
32 	bool			strip;
33 	bool			jit_mode;
34 	const char		*input_name;
35 	struct perf_data_file	output;
36 	u64			bytes_written;
37 	u64			aux_id;
38 	struct list_head	samples;
39 	struct itrace_synth_opts itrace_synth_opts;
40 };
41 
42 struct event_entry {
43 	struct list_head node;
44 	u32		 tid;
45 	union perf_event event[0];
46 };
47 
48 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
49 {
50 	ssize_t size;
51 
52 	size = perf_data_file__write(&inject->output, buf, sz);
53 	if (size < 0)
54 		return -errno;
55 
56 	inject->bytes_written += size;
57 	return 0;
58 }
59 
60 static int perf_event__repipe_synth(struct perf_tool *tool,
61 				    union perf_event *event)
62 {
63 	struct perf_inject *inject = container_of(tool, struct perf_inject,
64 						  tool);
65 
66 	return output_bytes(inject, event, event->header.size);
67 }
68 
69 static int perf_event__repipe_oe_synth(struct perf_tool *tool,
70 				       union perf_event *event,
71 				       struct ordered_events *oe __maybe_unused)
72 {
73 	return perf_event__repipe_synth(tool, event);
74 }
75 
76 #ifdef HAVE_LIBELF_SUPPORT
77 static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
78 			       union perf_event *event __maybe_unused,
79 			       struct ordered_events *oe __maybe_unused)
80 {
81 	return 0;
82 }
83 #endif
84 
85 static int perf_event__repipe_op2_synth(struct perf_tool *tool,
86 					union perf_event *event,
87 					struct perf_session *session
88 					__maybe_unused)
89 {
90 	return perf_event__repipe_synth(tool, event);
91 }
92 
93 static int perf_event__repipe_attr(struct perf_tool *tool,
94 				   union perf_event *event,
95 				   struct perf_evlist **pevlist)
96 {
97 	struct perf_inject *inject = container_of(tool, struct perf_inject,
98 						  tool);
99 	int ret;
100 
101 	ret = perf_event__process_attr(tool, event, pevlist);
102 	if (ret)
103 		return ret;
104 
105 	if (!inject->output.is_pipe)
106 		return 0;
107 
108 	return perf_event__repipe_synth(tool, event);
109 }
110 
111 #ifdef HAVE_AUXTRACE_SUPPORT
112 
113 static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
114 {
115 	char buf[4096];
116 	ssize_t ssz;
117 	int ret;
118 
119 	while (size > 0) {
120 		ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
121 		if (ssz < 0)
122 			return -errno;
123 		ret = output_bytes(inject, buf, ssz);
124 		if (ret)
125 			return ret;
126 		size -= ssz;
127 	}
128 
129 	return 0;
130 }
131 
132 static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
133 				       union perf_event *event,
134 				       struct perf_session *session
135 				       __maybe_unused)
136 {
137 	struct perf_inject *inject = container_of(tool, struct perf_inject,
138 						  tool);
139 	int ret;
140 
141 	inject->have_auxtrace = true;
142 
143 	if (!inject->output.is_pipe) {
144 		off_t offset;
145 
146 		offset = lseek(inject->output.fd, 0, SEEK_CUR);
147 		if (offset == -1)
148 			return -errno;
149 		ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
150 						     event, offset);
151 		if (ret < 0)
152 			return ret;
153 	}
154 
155 	if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
156 		ret = output_bytes(inject, event, event->header.size);
157 		if (ret < 0)
158 			return ret;
159 		ret = copy_bytes(inject, perf_data_file__fd(session->file),
160 				 event->auxtrace.size);
161 	} else {
162 		ret = output_bytes(inject, event,
163 				   event->header.size + event->auxtrace.size);
164 	}
165 	if (ret < 0)
166 		return ret;
167 
168 	return event->auxtrace.size;
169 }
170 
171 #else
172 
173 static s64
174 perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused,
175 			    union perf_event *event __maybe_unused,
176 			    struct perf_session *session __maybe_unused)
177 {
178 	pr_err("AUX area tracing not supported\n");
179 	return -EINVAL;
180 }
181 
182 #endif
183 
184 static int perf_event__repipe(struct perf_tool *tool,
185 			      union perf_event *event,
186 			      struct perf_sample *sample __maybe_unused,
187 			      struct machine *machine __maybe_unused)
188 {
189 	return perf_event__repipe_synth(tool, event);
190 }
191 
192 static int perf_event__drop(struct perf_tool *tool __maybe_unused,
193 			    union perf_event *event __maybe_unused,
194 			    struct perf_sample *sample __maybe_unused,
195 			    struct machine *machine __maybe_unused)
196 {
197 	return 0;
198 }
199 
200 static int perf_event__drop_aux(struct perf_tool *tool,
201 				union perf_event *event __maybe_unused,
202 				struct perf_sample *sample,
203 				struct machine *machine __maybe_unused)
204 {
205 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
206 
207 	if (!inject->aux_id)
208 		inject->aux_id = sample->id;
209 
210 	return 0;
211 }
212 
213 typedef int (*inject_handler)(struct perf_tool *tool,
214 			      union perf_event *event,
215 			      struct perf_sample *sample,
216 			      struct perf_evsel *evsel,
217 			      struct machine *machine);
218 
219 static int perf_event__repipe_sample(struct perf_tool *tool,
220 				     union perf_event *event,
221 				     struct perf_sample *sample,
222 				     struct perf_evsel *evsel,
223 				     struct machine *machine)
224 {
225 	if (evsel->handler) {
226 		inject_handler f = evsel->handler;
227 		return f(tool, event, sample, evsel, machine);
228 	}
229 
230 	build_id__mark_dso_hit(tool, event, sample, evsel, machine);
231 
232 	return perf_event__repipe_synth(tool, event);
233 }
234 
235 static int perf_event__repipe_mmap(struct perf_tool *tool,
236 				   union perf_event *event,
237 				   struct perf_sample *sample,
238 				   struct machine *machine)
239 {
240 	int err;
241 
242 	err = perf_event__process_mmap(tool, event, sample, machine);
243 	perf_event__repipe(tool, event, sample, machine);
244 
245 	return err;
246 }
247 
248 #ifdef HAVE_LIBELF_SUPPORT
249 static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
250 				       union perf_event *event,
251 				       struct perf_sample *sample,
252 				       struct machine *machine)
253 {
254 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
255 	u64 n = 0;
256 
257 	/*
258 	 * if jit marker, then inject jit mmaps and generate ELF images
259 	 */
260 	if (!jit_process(inject->session, &inject->output, machine,
261 			 event->mmap.filename, sample->pid, &n)) {
262 		inject->bytes_written += n;
263 		return 0;
264 	}
265 	return perf_event__repipe_mmap(tool, event, sample, machine);
266 }
267 #endif
268 
269 static int perf_event__repipe_mmap2(struct perf_tool *tool,
270 				   union perf_event *event,
271 				   struct perf_sample *sample,
272 				   struct machine *machine)
273 {
274 	int err;
275 
276 	err = perf_event__process_mmap2(tool, event, sample, machine);
277 	perf_event__repipe(tool, event, sample, machine);
278 
279 	return err;
280 }
281 
282 #ifdef HAVE_LIBELF_SUPPORT
283 static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
284 					union perf_event *event,
285 					struct perf_sample *sample,
286 					struct machine *machine)
287 {
288 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
289 	u64 n = 0;
290 
291 	/*
292 	 * if jit marker, then inject jit mmaps and generate ELF images
293 	 */
294 	if (!jit_process(inject->session, &inject->output, machine,
295 			  event->mmap2.filename, sample->pid, &n)) {
296 		inject->bytes_written += n;
297 		return 0;
298 	}
299 	return perf_event__repipe_mmap2(tool, event, sample, machine);
300 }
301 #endif
302 
303 static int perf_event__repipe_fork(struct perf_tool *tool,
304 				   union perf_event *event,
305 				   struct perf_sample *sample,
306 				   struct machine *machine)
307 {
308 	int err;
309 
310 	err = perf_event__process_fork(tool, event, sample, machine);
311 	perf_event__repipe(tool, event, sample, machine);
312 
313 	return err;
314 }
315 
316 static int perf_event__repipe_comm(struct perf_tool *tool,
317 				   union perf_event *event,
318 				   struct perf_sample *sample,
319 				   struct machine *machine)
320 {
321 	int err;
322 
323 	err = perf_event__process_comm(tool, event, sample, machine);
324 	perf_event__repipe(tool, event, sample, machine);
325 
326 	return err;
327 }
328 
329 static int perf_event__repipe_exit(struct perf_tool *tool,
330 				   union perf_event *event,
331 				   struct perf_sample *sample,
332 				   struct machine *machine)
333 {
334 	int err;
335 
336 	err = perf_event__process_exit(tool, event, sample, machine);
337 	perf_event__repipe(tool, event, sample, machine);
338 
339 	return err;
340 }
341 
342 static int perf_event__repipe_tracing_data(struct perf_tool *tool,
343 					   union perf_event *event,
344 					   struct perf_session *session)
345 {
346 	int err;
347 
348 	perf_event__repipe_synth(tool, event);
349 	err = perf_event__process_tracing_data(tool, event, session);
350 
351 	return err;
352 }
353 
354 static int perf_event__repipe_id_index(struct perf_tool *tool,
355 				       union perf_event *event,
356 				       struct perf_session *session)
357 {
358 	int err;
359 
360 	perf_event__repipe_synth(tool, event);
361 	err = perf_event__process_id_index(tool, event, session);
362 
363 	return err;
364 }
365 
366 static int dso__read_build_id(struct dso *dso)
367 {
368 	if (dso->has_build_id)
369 		return 0;
370 
371 	if (filename__read_build_id(dso->long_name, dso->build_id,
372 				    sizeof(dso->build_id)) > 0) {
373 		dso->has_build_id = true;
374 		return 0;
375 	}
376 
377 	return -1;
378 }
379 
380 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
381 				struct machine *machine)
382 {
383 	u16 misc = PERF_RECORD_MISC_USER;
384 	int err;
385 
386 	if (dso__read_build_id(dso) < 0) {
387 		pr_debug("no build_id found for %s\n", dso->long_name);
388 		return -1;
389 	}
390 
391 	if (dso->kernel)
392 		misc = PERF_RECORD_MISC_KERNEL;
393 
394 	err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
395 					      machine);
396 	if (err) {
397 		pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
398 		return -1;
399 	}
400 
401 	return 0;
402 }
403 
404 static int perf_event__inject_buildid(struct perf_tool *tool,
405 				      union perf_event *event,
406 				      struct perf_sample *sample,
407 				      struct perf_evsel *evsel __maybe_unused,
408 				      struct machine *machine)
409 {
410 	struct addr_location al;
411 	struct thread *thread;
412 	u8 cpumode;
413 
414 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
415 
416 	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
417 	if (thread == NULL) {
418 		pr_err("problem processing %d event, skipping it.\n",
419 		       event->header.type);
420 		goto repipe;
421 	}
422 
423 	thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
424 
425 	if (al.map != NULL) {
426 		if (!al.map->dso->hit) {
427 			al.map->dso->hit = 1;
428 			if (map__load(al.map, NULL) >= 0) {
429 				dso__inject_build_id(al.map->dso, tool, machine);
430 				/*
431 				 * If this fails, too bad, let the other side
432 				 * account this as unresolved.
433 				 */
434 			} else {
435 #ifdef HAVE_LIBELF_SUPPORT
436 				pr_warning("no symbols found in %s, maybe "
437 					   "install a debug package?\n",
438 					   al.map->dso->long_name);
439 #endif
440 			}
441 		}
442 	}
443 
444 	thread__put(thread);
445 repipe:
446 	perf_event__repipe(tool, event, sample, machine);
447 	return 0;
448 }
449 
450 static int perf_inject__sched_process_exit(struct perf_tool *tool,
451 					   union perf_event *event __maybe_unused,
452 					   struct perf_sample *sample,
453 					   struct perf_evsel *evsel __maybe_unused,
454 					   struct machine *machine __maybe_unused)
455 {
456 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
457 	struct event_entry *ent;
458 
459 	list_for_each_entry(ent, &inject->samples, node) {
460 		if (sample->tid == ent->tid) {
461 			list_del_init(&ent->node);
462 			free(ent);
463 			break;
464 		}
465 	}
466 
467 	return 0;
468 }
469 
470 static int perf_inject__sched_switch(struct perf_tool *tool,
471 				     union perf_event *event,
472 				     struct perf_sample *sample,
473 				     struct perf_evsel *evsel,
474 				     struct machine *machine)
475 {
476 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
477 	struct event_entry *ent;
478 
479 	perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
480 
481 	ent = malloc(event->header.size + sizeof(struct event_entry));
482 	if (ent == NULL) {
483 		color_fprintf(stderr, PERF_COLOR_RED,
484 			     "Not enough memory to process sched switch event!");
485 		return -1;
486 	}
487 
488 	ent->tid = sample->tid;
489 	memcpy(&ent->event, event, event->header.size);
490 	list_add(&ent->node, &inject->samples);
491 	return 0;
492 }
493 
494 static int perf_inject__sched_stat(struct perf_tool *tool,
495 				   union perf_event *event __maybe_unused,
496 				   struct perf_sample *sample,
497 				   struct perf_evsel *evsel,
498 				   struct machine *machine)
499 {
500 	struct event_entry *ent;
501 	union perf_event *event_sw;
502 	struct perf_sample sample_sw;
503 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
504 	u32 pid = perf_evsel__intval(evsel, sample, "pid");
505 
506 	list_for_each_entry(ent, &inject->samples, node) {
507 		if (pid == ent->tid)
508 			goto found;
509 	}
510 
511 	return 0;
512 found:
513 	event_sw = &ent->event[0];
514 	perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
515 
516 	sample_sw.period = sample->period;
517 	sample_sw.time	 = sample->time;
518 	perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
519 				      evsel->attr.read_format, &sample_sw,
520 				      false);
521 	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
522 	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
523 }
524 
525 static void sig_handler(int sig __maybe_unused)
526 {
527 	session_done = 1;
528 }
529 
530 static int perf_evsel__check_stype(struct perf_evsel *evsel,
531 				   u64 sample_type, const char *sample_msg)
532 {
533 	struct perf_event_attr *attr = &evsel->attr;
534 	const char *name = perf_evsel__name(evsel);
535 
536 	if (!(attr->sample_type & sample_type)) {
537 		pr_err("Samples for %s event do not have %s attribute set.",
538 			name, sample_msg);
539 		return -EINVAL;
540 	}
541 
542 	return 0;
543 }
544 
545 static int drop_sample(struct perf_tool *tool __maybe_unused,
546 		       union perf_event *event __maybe_unused,
547 		       struct perf_sample *sample __maybe_unused,
548 		       struct perf_evsel *evsel __maybe_unused,
549 		       struct machine *machine __maybe_unused)
550 {
551 	return 0;
552 }
553 
554 static void strip_init(struct perf_inject *inject)
555 {
556 	struct perf_evlist *evlist = inject->session->evlist;
557 	struct perf_evsel *evsel;
558 
559 	inject->tool.context_switch = perf_event__drop;
560 
561 	evlist__for_each(evlist, evsel)
562 		evsel->handler = drop_sample;
563 }
564 
565 static bool has_tracking(struct perf_evsel *evsel)
566 {
567 	return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm ||
568 	       evsel->attr.task;
569 }
570 
571 #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
572 		     PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER)
573 
574 /*
575  * In order that the perf.data file is parsable, tracking events like MMAP need
576  * their selected event to exist, except if there is only 1 selected event left
577  * and it has a compatible sample type.
578  */
579 static bool ok_to_remove(struct perf_evlist *evlist,
580 			 struct perf_evsel *evsel_to_remove)
581 {
582 	struct perf_evsel *evsel;
583 	int cnt = 0;
584 	bool ok = false;
585 
586 	if (!has_tracking(evsel_to_remove))
587 		return true;
588 
589 	evlist__for_each(evlist, evsel) {
590 		if (evsel->handler != drop_sample) {
591 			cnt += 1;
592 			if ((evsel->attr.sample_type & COMPAT_MASK) ==
593 			    (evsel_to_remove->attr.sample_type & COMPAT_MASK))
594 				ok = true;
595 		}
596 	}
597 
598 	return ok && cnt == 1;
599 }
600 
601 static void strip_fini(struct perf_inject *inject)
602 {
603 	struct perf_evlist *evlist = inject->session->evlist;
604 	struct perf_evsel *evsel, *tmp;
605 
606 	/* Remove non-synthesized evsels if possible */
607 	evlist__for_each_safe(evlist, tmp, evsel) {
608 		if (evsel->handler == drop_sample &&
609 		    ok_to_remove(evlist, evsel)) {
610 			pr_debug("Deleting %s\n", perf_evsel__name(evsel));
611 			perf_evlist__remove(evlist, evsel);
612 			perf_evsel__delete(evsel);
613 		}
614 	}
615 }
616 
617 static int __cmd_inject(struct perf_inject *inject)
618 {
619 	int ret = -EINVAL;
620 	struct perf_session *session = inject->session;
621 	struct perf_data_file *file_out = &inject->output;
622 	int fd = perf_data_file__fd(file_out);
623 	u64 output_data_offset;
624 
625 	signal(SIGINT, sig_handler);
626 
627 	if (inject->build_ids || inject->sched_stat ||
628 	    inject->itrace_synth_opts.set) {
629 		inject->tool.mmap	  = perf_event__repipe_mmap;
630 		inject->tool.mmap2	  = perf_event__repipe_mmap2;
631 		inject->tool.fork	  = perf_event__repipe_fork;
632 		inject->tool.tracing_data = perf_event__repipe_tracing_data;
633 	}
634 
635 	output_data_offset = session->header.data_offset;
636 
637 	if (inject->build_ids) {
638 		inject->tool.sample = perf_event__inject_buildid;
639 	} else if (inject->sched_stat) {
640 		struct perf_evsel *evsel;
641 
642 		evlist__for_each(session->evlist, evsel) {
643 			const char *name = perf_evsel__name(evsel);
644 
645 			if (!strcmp(name, "sched:sched_switch")) {
646 				if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
647 					return -EINVAL;
648 
649 				evsel->handler = perf_inject__sched_switch;
650 			} else if (!strcmp(name, "sched:sched_process_exit"))
651 				evsel->handler = perf_inject__sched_process_exit;
652 			else if (!strncmp(name, "sched:sched_stat_", 17))
653 				evsel->handler = perf_inject__sched_stat;
654 		}
655 	} else if (inject->itrace_synth_opts.set) {
656 		session->itrace_synth_opts = &inject->itrace_synth_opts;
657 		inject->itrace_synth_opts.inject = true;
658 		inject->tool.comm	    = perf_event__repipe_comm;
659 		inject->tool.exit	    = perf_event__repipe_exit;
660 		inject->tool.id_index	    = perf_event__repipe_id_index;
661 		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
662 		inject->tool.auxtrace	    = perf_event__process_auxtrace;
663 		inject->tool.aux	    = perf_event__drop_aux;
664 		inject->tool.itrace_start   = perf_event__drop_aux,
665 		inject->tool.ordered_events = true;
666 		inject->tool.ordering_requires_timestamps = true;
667 		/* Allow space in the header for new attributes */
668 		output_data_offset = 4096;
669 		if (inject->strip)
670 			strip_init(inject);
671 	}
672 
673 	if (!inject->itrace_synth_opts.set)
674 		auxtrace_index__free(&session->auxtrace_index);
675 
676 	if (!file_out->is_pipe)
677 		lseek(fd, output_data_offset, SEEK_SET);
678 
679 	ret = perf_session__process_events(session);
680 
681 	if (!file_out->is_pipe) {
682 		if (inject->build_ids) {
683 			perf_header__set_feat(&session->header,
684 					      HEADER_BUILD_ID);
685 			if (inject->have_auxtrace)
686 				dsos__hit_all(session);
687 		}
688 		/*
689 		 * The AUX areas have been removed and replaced with
690 		 * synthesized hardware events, so clear the feature flag and
691 		 * remove the evsel.
692 		 */
693 		if (inject->itrace_synth_opts.set) {
694 			struct perf_evsel *evsel;
695 
696 			perf_header__clear_feat(&session->header,
697 						HEADER_AUXTRACE);
698 			if (inject->itrace_synth_opts.last_branch)
699 				perf_header__set_feat(&session->header,
700 						      HEADER_BRANCH_STACK);
701 			evsel = perf_evlist__id2evsel_strict(session->evlist,
702 							     inject->aux_id);
703 			if (evsel) {
704 				pr_debug("Deleting %s\n",
705 					 perf_evsel__name(evsel));
706 				perf_evlist__remove(session->evlist, evsel);
707 				perf_evsel__delete(evsel);
708 			}
709 			if (inject->strip)
710 				strip_fini(inject);
711 		}
712 		session->header.data_offset = output_data_offset;
713 		session->header.data_size = inject->bytes_written;
714 		perf_session__write_header(session, session->evlist, fd, true);
715 	}
716 
717 	return ret;
718 }
719 
720 #ifdef HAVE_LIBELF_SUPPORT
721 static int
722 jit_validate_events(struct perf_session *session)
723 {
724 	struct perf_evsel *evsel;
725 
726 	/*
727 	 * check that all events use CLOCK_MONOTONIC
728 	 */
729 	evlist__for_each(session->evlist, evsel) {
730 		if (evsel->attr.use_clockid == 0 || evsel->attr.clockid != CLOCK_MONOTONIC)
731 			return -1;
732 	}
733 	return 0;
734 }
735 #endif
736 
737 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
738 {
739 	struct perf_inject inject = {
740 		.tool = {
741 			.sample		= perf_event__repipe_sample,
742 			.mmap		= perf_event__repipe,
743 			.mmap2		= perf_event__repipe,
744 			.comm		= perf_event__repipe,
745 			.fork		= perf_event__repipe,
746 			.exit		= perf_event__repipe,
747 			.lost		= perf_event__repipe,
748 			.lost_samples	= perf_event__repipe,
749 			.aux		= perf_event__repipe,
750 			.itrace_start	= perf_event__repipe,
751 			.context_switch	= perf_event__repipe,
752 			.read		= perf_event__repipe_sample,
753 			.throttle	= perf_event__repipe,
754 			.unthrottle	= perf_event__repipe,
755 			.attr		= perf_event__repipe_attr,
756 			.tracing_data	= perf_event__repipe_op2_synth,
757 			.auxtrace_info	= perf_event__repipe_op2_synth,
758 			.auxtrace	= perf_event__repipe_auxtrace,
759 			.auxtrace_error	= perf_event__repipe_op2_synth,
760 			.finished_round	= perf_event__repipe_oe_synth,
761 			.build_id	= perf_event__repipe_op2_synth,
762 			.id_index	= perf_event__repipe_op2_synth,
763 		},
764 		.input_name  = "-",
765 		.samples = LIST_HEAD_INIT(inject.samples),
766 		.output = {
767 			.path = "-",
768 			.mode = PERF_DATA_MODE_WRITE,
769 		},
770 	};
771 	struct perf_data_file file = {
772 		.mode = PERF_DATA_MODE_READ,
773 	};
774 	int ret;
775 
776 	struct option options[] = {
777 		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
778 			    "Inject build-ids into the output stream"),
779 		OPT_STRING('i', "input", &inject.input_name, "file",
780 			   "input file name"),
781 		OPT_STRING('o', "output", &inject.output.path, "file",
782 			   "output file name"),
783 		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
784 			    "Merge sched-stat and sched-switch for getting events "
785 			    "where and how long tasks slept"),
786 		OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
787 		OPT_INCR('v', "verbose", &verbose,
788 			 "be more verbose (show build ids, etc)"),
789 		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
790 			   "kallsyms pathname"),
791 		OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
792 		OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
793 				    NULL, "opts", "Instruction Tracing options",
794 				    itrace_parse_synth_opts),
795 		OPT_BOOLEAN(0, "strip", &inject.strip,
796 			    "strip non-synthesized events (use with --itrace)"),
797 		OPT_END()
798 	};
799 	const char * const inject_usage[] = {
800 		"perf inject [<options>]",
801 		NULL
802 	};
803 #ifndef HAVE_LIBELF_SUPPORT
804 	set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
805 #endif
806 	argc = parse_options(argc, argv, options, inject_usage, 0);
807 
808 	/*
809 	 * Any (unrecognized) arguments left?
810 	 */
811 	if (argc)
812 		usage_with_options(inject_usage, options);
813 
814 	if (inject.strip && !inject.itrace_synth_opts.set) {
815 		pr_err("--strip option requires --itrace option\n");
816 		return -1;
817 	}
818 
819 	if (perf_data_file__open(&inject.output)) {
820 		perror("failed to create output file");
821 		return -1;
822 	}
823 
824 	inject.tool.ordered_events = inject.sched_stat;
825 
826 	file.path = inject.input_name;
827 	inject.session = perf_session__new(&file, true, &inject.tool);
828 	if (inject.session == NULL)
829 		return -1;
830 
831 	if (inject.build_ids) {
832 		/*
833 		 * to make sure the mmap records are ordered correctly
834 		 * and so that the correct especially due to jitted code
835 		 * mmaps. We cannot generate the buildid hit list and
836 		 * inject the jit mmaps at the same time for now.
837 		 */
838 		inject.tool.ordered_events = true;
839 		inject.tool.ordering_requires_timestamps = true;
840 	}
841 #ifdef HAVE_LIBELF_SUPPORT
842 	if (inject.jit_mode) {
843 		/*
844 		 * validate event is using the correct clockid
845 		 */
846 		if (jit_validate_events(inject.session)) {
847 			fprintf(stderr, "error, jitted code must be sampled with perf record -k 1\n");
848 			return -1;
849 		}
850 		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
851 		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
852 		inject.tool.ordered_events = true;
853 		inject.tool.ordering_requires_timestamps = true;
854 		/*
855 		 * JIT MMAP injection injects all MMAP events in one go, so it
856 		 * does not obey finished_round semantics.
857 		 */
858 		inject.tool.finished_round = perf_event__drop_oe;
859 	}
860 #endif
861 	ret = symbol__init(&inject.session->header.env);
862 	if (ret < 0)
863 		goto out_delete;
864 
865 	ret = __cmd_inject(&inject);
866 
867 out_delete:
868 	perf_session__delete(inject.session);
869 	return ret;
870 }
871