Merge tag 'armsoc-defconfig' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[cascardo/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
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 }