xref: /linux/tools/perf/builtin-inject.c (revision 3b812ecce736432e6b55e77028ea387eb1517d24)
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_JITDUMP
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_JITDUMP
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 	int ret;
257 
258 	/*
259 	 * if jit marker, then inject jit mmaps and generate ELF images
260 	 */
261 	ret = jit_process(inject->session, &inject->output, machine,
262 			  event->mmap.filename, sample->pid, &n);
263 	if (ret < 0)
264 		return ret;
265 	if (ret) {
266 		inject->bytes_written += n;
267 		return 0;
268 	}
269 	return perf_event__repipe_mmap(tool, event, sample, machine);
270 }
271 #endif
272 
273 static int perf_event__repipe_mmap2(struct perf_tool *tool,
274 				   union perf_event *event,
275 				   struct perf_sample *sample,
276 				   struct machine *machine)
277 {
278 	int err;
279 
280 	err = perf_event__process_mmap2(tool, event, sample, machine);
281 	perf_event__repipe(tool, event, sample, machine);
282 
283 	return err;
284 }
285 
286 #ifdef HAVE_JITDUMP
287 static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
288 					union perf_event *event,
289 					struct perf_sample *sample,
290 					struct machine *machine)
291 {
292 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
293 	u64 n = 0;
294 	int ret;
295 
296 	/*
297 	 * if jit marker, then inject jit mmaps and generate ELF images
298 	 */
299 	ret = jit_process(inject->session, &inject->output, machine,
300 			  event->mmap2.filename, sample->pid, &n);
301 	if (ret < 0)
302 		return ret;
303 	if (ret) {
304 		inject->bytes_written += n;
305 		return 0;
306 	}
307 	return perf_event__repipe_mmap2(tool, event, sample, machine);
308 }
309 #endif
310 
311 static int perf_event__repipe_fork(struct perf_tool *tool,
312 				   union perf_event *event,
313 				   struct perf_sample *sample,
314 				   struct machine *machine)
315 {
316 	int err;
317 
318 	err = perf_event__process_fork(tool, event, sample, machine);
319 	perf_event__repipe(tool, event, sample, machine);
320 
321 	return err;
322 }
323 
324 static int perf_event__repipe_comm(struct perf_tool *tool,
325 				   union perf_event *event,
326 				   struct perf_sample *sample,
327 				   struct machine *machine)
328 {
329 	int err;
330 
331 	err = perf_event__process_comm(tool, event, sample, machine);
332 	perf_event__repipe(tool, event, sample, machine);
333 
334 	return err;
335 }
336 
337 static int perf_event__repipe_exit(struct perf_tool *tool,
338 				   union perf_event *event,
339 				   struct perf_sample *sample,
340 				   struct machine *machine)
341 {
342 	int err;
343 
344 	err = perf_event__process_exit(tool, event, sample, machine);
345 	perf_event__repipe(tool, event, sample, machine);
346 
347 	return err;
348 }
349 
350 static int perf_event__repipe_tracing_data(struct perf_tool *tool,
351 					   union perf_event *event,
352 					   struct perf_session *session)
353 {
354 	int err;
355 
356 	perf_event__repipe_synth(tool, event);
357 	err = perf_event__process_tracing_data(tool, event, session);
358 
359 	return err;
360 }
361 
362 static int perf_event__repipe_id_index(struct perf_tool *tool,
363 				       union perf_event *event,
364 				       struct perf_session *session)
365 {
366 	int err;
367 
368 	perf_event__repipe_synth(tool, event);
369 	err = perf_event__process_id_index(tool, event, session);
370 
371 	return err;
372 }
373 
374 static int dso__read_build_id(struct dso *dso)
375 {
376 	if (dso->has_build_id)
377 		return 0;
378 
379 	if (filename__read_build_id(dso->long_name, dso->build_id,
380 				    sizeof(dso->build_id)) > 0) {
381 		dso->has_build_id = true;
382 		return 0;
383 	}
384 
385 	return -1;
386 }
387 
388 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
389 				struct machine *machine)
390 {
391 	u16 misc = PERF_RECORD_MISC_USER;
392 	int err;
393 
394 	if (dso__read_build_id(dso) < 0) {
395 		pr_debug("no build_id found for %s\n", dso->long_name);
396 		return -1;
397 	}
398 
399 	if (dso->kernel)
400 		misc = PERF_RECORD_MISC_KERNEL;
401 
402 	err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
403 					      machine);
404 	if (err) {
405 		pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
406 		return -1;
407 	}
408 
409 	return 0;
410 }
411 
412 static int perf_event__inject_buildid(struct perf_tool *tool,
413 				      union perf_event *event,
414 				      struct perf_sample *sample,
415 				      struct perf_evsel *evsel __maybe_unused,
416 				      struct machine *machine)
417 {
418 	struct addr_location al;
419 	struct thread *thread;
420 	u8 cpumode;
421 
422 	cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
423 
424 	thread = machine__findnew_thread(machine, sample->pid, sample->tid);
425 	if (thread == NULL) {
426 		pr_err("problem processing %d event, skipping it.\n",
427 		       event->header.type);
428 		goto repipe;
429 	}
430 
431 	thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
432 
433 	if (al.map != NULL) {
434 		if (!al.map->dso->hit) {
435 			al.map->dso->hit = 1;
436 			if (map__load(al.map, NULL) >= 0) {
437 				dso__inject_build_id(al.map->dso, tool, machine);
438 				/*
439 				 * If this fails, too bad, let the other side
440 				 * account this as unresolved.
441 				 */
442 			} else {
443 #ifdef HAVE_LIBELF_SUPPORT
444 				pr_warning("no symbols found in %s, maybe "
445 					   "install a debug package?\n",
446 					   al.map->dso->long_name);
447 #endif
448 			}
449 		}
450 	}
451 
452 	thread__put(thread);
453 repipe:
454 	perf_event__repipe(tool, event, sample, machine);
455 	return 0;
456 }
457 
458 static int perf_inject__sched_process_exit(struct perf_tool *tool,
459 					   union perf_event *event __maybe_unused,
460 					   struct perf_sample *sample,
461 					   struct perf_evsel *evsel __maybe_unused,
462 					   struct machine *machine __maybe_unused)
463 {
464 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
465 	struct event_entry *ent;
466 
467 	list_for_each_entry(ent, &inject->samples, node) {
468 		if (sample->tid == ent->tid) {
469 			list_del_init(&ent->node);
470 			free(ent);
471 			break;
472 		}
473 	}
474 
475 	return 0;
476 }
477 
478 static int perf_inject__sched_switch(struct perf_tool *tool,
479 				     union perf_event *event,
480 				     struct perf_sample *sample,
481 				     struct perf_evsel *evsel,
482 				     struct machine *machine)
483 {
484 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
485 	struct event_entry *ent;
486 
487 	perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
488 
489 	ent = malloc(event->header.size + sizeof(struct event_entry));
490 	if (ent == NULL) {
491 		color_fprintf(stderr, PERF_COLOR_RED,
492 			     "Not enough memory to process sched switch event!");
493 		return -1;
494 	}
495 
496 	ent->tid = sample->tid;
497 	memcpy(&ent->event, event, event->header.size);
498 	list_add(&ent->node, &inject->samples);
499 	return 0;
500 }
501 
502 static int perf_inject__sched_stat(struct perf_tool *tool,
503 				   union perf_event *event __maybe_unused,
504 				   struct perf_sample *sample,
505 				   struct perf_evsel *evsel,
506 				   struct machine *machine)
507 {
508 	struct event_entry *ent;
509 	union perf_event *event_sw;
510 	struct perf_sample sample_sw;
511 	struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
512 	u32 pid = perf_evsel__intval(evsel, sample, "pid");
513 
514 	list_for_each_entry(ent, &inject->samples, node) {
515 		if (pid == ent->tid)
516 			goto found;
517 	}
518 
519 	return 0;
520 found:
521 	event_sw = &ent->event[0];
522 	perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
523 
524 	sample_sw.period = sample->period;
525 	sample_sw.time	 = sample->time;
526 	perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
527 				      evsel->attr.read_format, &sample_sw,
528 				      false);
529 	build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
530 	return perf_event__repipe(tool, event_sw, &sample_sw, machine);
531 }
532 
533 static void sig_handler(int sig __maybe_unused)
534 {
535 	session_done = 1;
536 }
537 
538 static int perf_evsel__check_stype(struct perf_evsel *evsel,
539 				   u64 sample_type, const char *sample_msg)
540 {
541 	struct perf_event_attr *attr = &evsel->attr;
542 	const char *name = perf_evsel__name(evsel);
543 
544 	if (!(attr->sample_type & sample_type)) {
545 		pr_err("Samples for %s event do not have %s attribute set.",
546 			name, sample_msg);
547 		return -EINVAL;
548 	}
549 
550 	return 0;
551 }
552 
553 static int drop_sample(struct perf_tool *tool __maybe_unused,
554 		       union perf_event *event __maybe_unused,
555 		       struct perf_sample *sample __maybe_unused,
556 		       struct perf_evsel *evsel __maybe_unused,
557 		       struct machine *machine __maybe_unused)
558 {
559 	return 0;
560 }
561 
562 static void strip_init(struct perf_inject *inject)
563 {
564 	struct perf_evlist *evlist = inject->session->evlist;
565 	struct perf_evsel *evsel;
566 
567 	inject->tool.context_switch = perf_event__drop;
568 
569 	evlist__for_each(evlist, evsel)
570 		evsel->handler = drop_sample;
571 }
572 
573 static bool has_tracking(struct perf_evsel *evsel)
574 {
575 	return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm ||
576 	       evsel->attr.task;
577 }
578 
579 #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
580 		     PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER)
581 
582 /*
583  * In order that the perf.data file is parsable, tracking events like MMAP need
584  * their selected event to exist, except if there is only 1 selected event left
585  * and it has a compatible sample type.
586  */
587 static bool ok_to_remove(struct perf_evlist *evlist,
588 			 struct perf_evsel *evsel_to_remove)
589 {
590 	struct perf_evsel *evsel;
591 	int cnt = 0;
592 	bool ok = false;
593 
594 	if (!has_tracking(evsel_to_remove))
595 		return true;
596 
597 	evlist__for_each(evlist, evsel) {
598 		if (evsel->handler != drop_sample) {
599 			cnt += 1;
600 			if ((evsel->attr.sample_type & COMPAT_MASK) ==
601 			    (evsel_to_remove->attr.sample_type & COMPAT_MASK))
602 				ok = true;
603 		}
604 	}
605 
606 	return ok && cnt == 1;
607 }
608 
609 static void strip_fini(struct perf_inject *inject)
610 {
611 	struct perf_evlist *evlist = inject->session->evlist;
612 	struct perf_evsel *evsel, *tmp;
613 
614 	/* Remove non-synthesized evsels if possible */
615 	evlist__for_each_safe(evlist, tmp, evsel) {
616 		if (evsel->handler == drop_sample &&
617 		    ok_to_remove(evlist, evsel)) {
618 			pr_debug("Deleting %s\n", perf_evsel__name(evsel));
619 			perf_evlist__remove(evlist, evsel);
620 			perf_evsel__delete(evsel);
621 		}
622 	}
623 }
624 
625 static int __cmd_inject(struct perf_inject *inject)
626 {
627 	int ret = -EINVAL;
628 	struct perf_session *session = inject->session;
629 	struct perf_data_file *file_out = &inject->output;
630 	int fd = perf_data_file__fd(file_out);
631 	u64 output_data_offset;
632 
633 	signal(SIGINT, sig_handler);
634 
635 	if (inject->build_ids || inject->sched_stat ||
636 	    inject->itrace_synth_opts.set) {
637 		inject->tool.mmap	  = perf_event__repipe_mmap;
638 		inject->tool.mmap2	  = perf_event__repipe_mmap2;
639 		inject->tool.fork	  = perf_event__repipe_fork;
640 		inject->tool.tracing_data = perf_event__repipe_tracing_data;
641 	}
642 
643 	output_data_offset = session->header.data_offset;
644 
645 	if (inject->build_ids) {
646 		inject->tool.sample = perf_event__inject_buildid;
647 	} else if (inject->sched_stat) {
648 		struct perf_evsel *evsel;
649 
650 		evlist__for_each(session->evlist, evsel) {
651 			const char *name = perf_evsel__name(evsel);
652 
653 			if (!strcmp(name, "sched:sched_switch")) {
654 				if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
655 					return -EINVAL;
656 
657 				evsel->handler = perf_inject__sched_switch;
658 			} else if (!strcmp(name, "sched:sched_process_exit"))
659 				evsel->handler = perf_inject__sched_process_exit;
660 			else if (!strncmp(name, "sched:sched_stat_", 17))
661 				evsel->handler = perf_inject__sched_stat;
662 		}
663 	} else if (inject->itrace_synth_opts.set) {
664 		session->itrace_synth_opts = &inject->itrace_synth_opts;
665 		inject->itrace_synth_opts.inject = true;
666 		inject->tool.comm	    = perf_event__repipe_comm;
667 		inject->tool.exit	    = perf_event__repipe_exit;
668 		inject->tool.id_index	    = perf_event__repipe_id_index;
669 		inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
670 		inject->tool.auxtrace	    = perf_event__process_auxtrace;
671 		inject->tool.aux	    = perf_event__drop_aux;
672 		inject->tool.itrace_start   = perf_event__drop_aux,
673 		inject->tool.ordered_events = true;
674 		inject->tool.ordering_requires_timestamps = true;
675 		/* Allow space in the header for new attributes */
676 		output_data_offset = 4096;
677 		if (inject->strip)
678 			strip_init(inject);
679 	}
680 
681 	if (!inject->itrace_synth_opts.set)
682 		auxtrace_index__free(&session->auxtrace_index);
683 
684 	if (!file_out->is_pipe)
685 		lseek(fd, output_data_offset, SEEK_SET);
686 
687 	ret = perf_session__process_events(session);
688 
689 	if (!file_out->is_pipe) {
690 		if (inject->build_ids)
691 			perf_header__set_feat(&session->header,
692 					      HEADER_BUILD_ID);
693 		/*
694 		 * Keep all buildids when there is unprocessed AUX data because
695 		 * it is not known which ones the AUX trace hits.
696 		 */
697 		if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
698 		    inject->have_auxtrace && !inject->itrace_synth_opts.set)
699 			dsos__hit_all(session);
700 		/*
701 		 * The AUX areas have been removed and replaced with
702 		 * synthesized hardware events, so clear the feature flag and
703 		 * remove the evsel.
704 		 */
705 		if (inject->itrace_synth_opts.set) {
706 			struct perf_evsel *evsel;
707 
708 			perf_header__clear_feat(&session->header,
709 						HEADER_AUXTRACE);
710 			if (inject->itrace_synth_opts.last_branch)
711 				perf_header__set_feat(&session->header,
712 						      HEADER_BRANCH_STACK);
713 			evsel = perf_evlist__id2evsel_strict(session->evlist,
714 							     inject->aux_id);
715 			if (evsel) {
716 				pr_debug("Deleting %s\n",
717 					 perf_evsel__name(evsel));
718 				perf_evlist__remove(session->evlist, evsel);
719 				perf_evsel__delete(evsel);
720 			}
721 			if (inject->strip)
722 				strip_fini(inject);
723 		}
724 		session->header.data_offset = output_data_offset;
725 		session->header.data_size = inject->bytes_written;
726 		perf_session__write_header(session, session->evlist, fd, true);
727 	}
728 
729 	return ret;
730 }
731 
732 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
733 {
734 	struct perf_inject inject = {
735 		.tool = {
736 			.sample		= perf_event__repipe_sample,
737 			.mmap		= perf_event__repipe,
738 			.mmap2		= perf_event__repipe,
739 			.comm		= perf_event__repipe,
740 			.fork		= perf_event__repipe,
741 			.exit		= perf_event__repipe,
742 			.lost		= perf_event__repipe,
743 			.lost_samples	= perf_event__repipe,
744 			.aux		= perf_event__repipe,
745 			.itrace_start	= perf_event__repipe,
746 			.context_switch	= perf_event__repipe,
747 			.read		= perf_event__repipe_sample,
748 			.throttle	= perf_event__repipe,
749 			.unthrottle	= perf_event__repipe,
750 			.attr		= perf_event__repipe_attr,
751 			.tracing_data	= perf_event__repipe_op2_synth,
752 			.auxtrace_info	= perf_event__repipe_op2_synth,
753 			.auxtrace	= perf_event__repipe_auxtrace,
754 			.auxtrace_error	= perf_event__repipe_op2_synth,
755 			.finished_round	= perf_event__repipe_oe_synth,
756 			.build_id	= perf_event__repipe_op2_synth,
757 			.id_index	= perf_event__repipe_op2_synth,
758 		},
759 		.input_name  = "-",
760 		.samples = LIST_HEAD_INIT(inject.samples),
761 		.output = {
762 			.path = "-",
763 			.mode = PERF_DATA_MODE_WRITE,
764 		},
765 	};
766 	struct perf_data_file file = {
767 		.mode = PERF_DATA_MODE_READ,
768 	};
769 	int ret;
770 
771 	struct option options[] = {
772 		OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
773 			    "Inject build-ids into the output stream"),
774 		OPT_STRING('i', "input", &inject.input_name, "file",
775 			   "input file name"),
776 		OPT_STRING('o', "output", &inject.output.path, "file",
777 			   "output file name"),
778 		OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
779 			    "Merge sched-stat and sched-switch for getting events "
780 			    "where and how long tasks slept"),
781 #ifdef HAVE_JITDUMP
782 		OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
783 #endif
784 		OPT_INCR('v', "verbose", &verbose,
785 			 "be more verbose (show build ids, etc)"),
786 		OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
787 			   "kallsyms pathname"),
788 		OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
789 		OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
790 				    NULL, "opts", "Instruction Tracing options",
791 				    itrace_parse_synth_opts),
792 		OPT_BOOLEAN(0, "strip", &inject.strip,
793 			    "strip non-synthesized events (use with --itrace)"),
794 		OPT_END()
795 	};
796 	const char * const inject_usage[] = {
797 		"perf inject [<options>]",
798 		NULL
799 	};
800 #ifndef HAVE_JITDUMP
801 	set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
802 #endif
803 	argc = parse_options(argc, argv, options, inject_usage, 0);
804 
805 	/*
806 	 * Any (unrecognized) arguments left?
807 	 */
808 	if (argc)
809 		usage_with_options(inject_usage, options);
810 
811 	if (inject.strip && !inject.itrace_synth_opts.set) {
812 		pr_err("--strip option requires --itrace option\n");
813 		return -1;
814 	}
815 
816 	if (perf_data_file__open(&inject.output)) {
817 		perror("failed to create output file");
818 		return -1;
819 	}
820 
821 	inject.tool.ordered_events = inject.sched_stat;
822 
823 	file.path = inject.input_name;
824 	inject.session = perf_session__new(&file, true, &inject.tool);
825 	if (inject.session == NULL)
826 		return -1;
827 
828 	if (inject.build_ids) {
829 		/*
830 		 * to make sure the mmap records are ordered correctly
831 		 * and so that the correct especially due to jitted code
832 		 * mmaps. We cannot generate the buildid hit list and
833 		 * inject the jit mmaps at the same time for now.
834 		 */
835 		inject.tool.ordered_events = true;
836 		inject.tool.ordering_requires_timestamps = true;
837 	}
838 #ifdef HAVE_JITDUMP
839 	if (inject.jit_mode) {
840 		inject.tool.mmap2	   = perf_event__jit_repipe_mmap2;
841 		inject.tool.mmap	   = perf_event__jit_repipe_mmap;
842 		inject.tool.ordered_events = true;
843 		inject.tool.ordering_requires_timestamps = true;
844 		/*
845 		 * JIT MMAP injection injects all MMAP events in one go, so it
846 		 * does not obey finished_round semantics.
847 		 */
848 		inject.tool.finished_round = perf_event__drop_oe;
849 	}
850 #endif
851 	ret = symbol__init(&inject.session->header.env);
852 	if (ret < 0)
853 		goto out_delete;
854 
855 	ret = __cmd_inject(&inject);
856 
857 out_delete:
858 	perf_session__delete(inject.session);
859 	return ret;
860 }
861