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