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