]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/builtin-inject.c
23a76cf3846f4605834af2d405296a898e0869f5
[linux.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 "util/color.h"
12 #include "util/dso.h"
13 #include "util/evlist.h"
14 #include "util/evsel.h"
15 #include "util/map.h"
16 #include "util/session.h"
17 #include "util/tool.h"
18 #include "util/debug.h"
19 #include "util/build-id.h"
20 #include "util/data.h"
21 #include "util/auxtrace.h"
22 #include "util/jit.h"
23 #include "util/symbol.h"
24 #include "util/synthetic-events.h"
25 #include "util/thread.h"
26
27 #include <subcmd/parse-options.h>
28
29 #include <linux/list.h>
30 #include <errno.h>
31 #include <signal.h>
32
33 struct perf_inject {
34         struct perf_tool        tool;
35         struct perf_session     *session;
36         bool                    build_ids;
37         bool                    sched_stat;
38         bool                    have_auxtrace;
39         bool                    strip;
40         bool                    jit_mode;
41         const char              *input_name;
42         struct perf_data        output;
43         u64                     bytes_written;
44         u64                     aux_id;
45         struct list_head        samples;
46         struct itrace_synth_opts itrace_synth_opts;
47 };
48
49 struct event_entry {
50         struct list_head node;
51         u32              tid;
52         union perf_event event[0];
53 };
54
55 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
56 {
57         ssize_t size;
58
59         size = perf_data__write(&inject->output, buf, sz);
60         if (size < 0)
61                 return -errno;
62
63         inject->bytes_written += size;
64         return 0;
65 }
66
67 static int perf_event__repipe_synth(struct perf_tool *tool,
68                                     union perf_event *event)
69 {
70         struct perf_inject *inject = container_of(tool, struct perf_inject,
71                                                   tool);
72
73         return output_bytes(inject, event, event->header.size);
74 }
75
76 static int perf_event__repipe_oe_synth(struct perf_tool *tool,
77                                        union perf_event *event,
78                                        struct ordered_events *oe __maybe_unused)
79 {
80         return perf_event__repipe_synth(tool, event);
81 }
82
83 #ifdef HAVE_JITDUMP
84 static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
85                                union perf_event *event __maybe_unused,
86                                struct ordered_events *oe __maybe_unused)
87 {
88         return 0;
89 }
90 #endif
91
92 static int perf_event__repipe_op2_synth(struct perf_session *session,
93                                         union perf_event *event)
94 {
95         return perf_event__repipe_synth(session->tool, event);
96 }
97
98 static int perf_event__repipe_attr(struct perf_tool *tool,
99                                    union perf_event *event,
100                                    struct evlist **pevlist)
101 {
102         struct perf_inject *inject = container_of(tool, struct perf_inject,
103                                                   tool);
104         int ret;
105
106         ret = perf_event__process_attr(tool, event, pevlist);
107         if (ret)
108                 return ret;
109
110         if (!inject->output.is_pipe)
111                 return 0;
112
113         return perf_event__repipe_synth(tool, event);
114 }
115
116 #ifdef HAVE_AUXTRACE_SUPPORT
117
118 static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
119 {
120         char buf[4096];
121         ssize_t ssz;
122         int ret;
123
124         while (size > 0) {
125                 ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
126                 if (ssz < 0)
127                         return -errno;
128                 ret = output_bytes(inject, buf, ssz);
129                 if (ret)
130                         return ret;
131                 size -= ssz;
132         }
133
134         return 0;
135 }
136
137 static s64 perf_event__repipe_auxtrace(struct perf_session *session,
138                                        union perf_event *event)
139 {
140         struct perf_tool *tool = session->tool;
141         struct perf_inject *inject = container_of(tool, struct perf_inject,
142                                                   tool);
143         int ret;
144
145         inject->have_auxtrace = true;
146
147         if (!inject->output.is_pipe) {
148                 off_t offset;
149
150                 offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
151                 if (offset == -1)
152                         return -errno;
153                 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
154                                                      event, offset);
155                 if (ret < 0)
156                         return ret;
157         }
158
159         if (perf_data__is_pipe(session->data) || !session->one_mmap) {
160                 ret = output_bytes(inject, event, event->header.size);
161                 if (ret < 0)
162                         return ret;
163                 ret = copy_bytes(inject, perf_data__fd(session->data),
164                                  event->auxtrace.size);
165         } else {
166                 ret = output_bytes(inject, event,
167                                    event->header.size + event->auxtrace.size);
168         }
169         if (ret < 0)
170                 return ret;
171
172         return event->auxtrace.size;
173 }
174
175 #else
176
177 static s64
178 perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
179                             union perf_event *event __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 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 evsel *evsel,
226                                      struct machine *machine)
227 {
228         if (evsel && 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_session *session,
366                                            union perf_event *event)
367 {
368         int err;
369
370         perf_event__repipe_synth(session->tool, event);
371         err = perf_event__process_tracing_data(session, event);
372
373         return err;
374 }
375
376 static int perf_event__repipe_id_index(struct perf_session *session,
377                                        union perf_event *event)
378 {
379         int err;
380
381         perf_event__repipe_synth(session->tool, event);
382         err = perf_event__process_id_index(session, event);
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 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         if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
442                 if (!al.map->dso->hit) {
443                         al.map->dso->hit = 1;
444                         if (map__load(al.map) >= 0) {
445                                 dso__inject_build_id(al.map->dso, tool, machine);
446                                 /*
447                                  * If this fails, too bad, let the other side
448                                  * account this as unresolved.
449                                  */
450                         } else {
451 #ifdef HAVE_LIBELF_SUPPORT
452                                 pr_warning("no symbols found in %s, maybe "
453                                            "install a debug package?\n",
454                                            al.map->dso->long_name);
455 #endif
456                         }
457                 }
458         }
459
460         thread__put(thread);
461 repipe:
462         perf_event__repipe(tool, event, sample, machine);
463         return 0;
464 }
465
466 static int perf_inject__sched_process_exit(struct perf_tool *tool,
467                                            union perf_event *event __maybe_unused,
468                                            struct perf_sample *sample,
469                                            struct evsel *evsel __maybe_unused,
470                                            struct machine *machine __maybe_unused)
471 {
472         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
473         struct event_entry *ent;
474
475         list_for_each_entry(ent, &inject->samples, node) {
476                 if (sample->tid == ent->tid) {
477                         list_del_init(&ent->node);
478                         free(ent);
479                         break;
480                 }
481         }
482
483         return 0;
484 }
485
486 static int perf_inject__sched_switch(struct perf_tool *tool,
487                                      union perf_event *event,
488                                      struct perf_sample *sample,
489                                      struct evsel *evsel,
490                                      struct machine *machine)
491 {
492         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
493         struct event_entry *ent;
494
495         perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
496
497         ent = malloc(event->header.size + sizeof(struct event_entry));
498         if (ent == NULL) {
499                 color_fprintf(stderr, PERF_COLOR_RED,
500                              "Not enough memory to process sched switch event!");
501                 return -1;
502         }
503
504         ent->tid = sample->tid;
505         memcpy(&ent->event, event, event->header.size);
506         list_add(&ent->node, &inject->samples);
507         return 0;
508 }
509
510 static int perf_inject__sched_stat(struct perf_tool *tool,
511                                    union perf_event *event __maybe_unused,
512                                    struct perf_sample *sample,
513                                    struct evsel *evsel,
514                                    struct machine *machine)
515 {
516         struct event_entry *ent;
517         union perf_event *event_sw;
518         struct perf_sample sample_sw;
519         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
520         u32 pid = perf_evsel__intval(evsel, sample, "pid");
521
522         list_for_each_entry(ent, &inject->samples, node) {
523                 if (pid == ent->tid)
524                         goto found;
525         }
526
527         return 0;
528 found:
529         event_sw = &ent->event[0];
530         perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
531
532         sample_sw.period = sample->period;
533         sample_sw.time   = sample->time;
534         perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type,
535                                       evsel->core.attr.read_format, &sample_sw);
536         build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
537         return perf_event__repipe(tool, event_sw, &sample_sw, machine);
538 }
539
540 static void sig_handler(int sig __maybe_unused)
541 {
542         session_done = 1;
543 }
544
545 static int perf_evsel__check_stype(struct evsel *evsel,
546                                    u64 sample_type, const char *sample_msg)
547 {
548         struct perf_event_attr *attr = &evsel->core.attr;
549         const char *name = perf_evsel__name(evsel);
550
551         if (!(attr->sample_type & sample_type)) {
552                 pr_err("Samples for %s event do not have %s attribute set.",
553                         name, sample_msg);
554                 return -EINVAL;
555         }
556
557         return 0;
558 }
559
560 static int drop_sample(struct perf_tool *tool __maybe_unused,
561                        union perf_event *event __maybe_unused,
562                        struct perf_sample *sample __maybe_unused,
563                        struct evsel *evsel __maybe_unused,
564                        struct machine *machine __maybe_unused)
565 {
566         return 0;
567 }
568
569 static void strip_init(struct perf_inject *inject)
570 {
571         struct evlist *evlist = inject->session->evlist;
572         struct evsel *evsel;
573
574         inject->tool.context_switch = perf_event__drop;
575
576         evlist__for_each_entry(evlist, evsel)
577                 evsel->handler = drop_sample;
578 }
579
580 static bool has_tracking(struct evsel *evsel)
581 {
582         return evsel->core.attr.mmap || evsel->core.attr.mmap2 || evsel->core.attr.comm ||
583                evsel->core.attr.task;
584 }
585
586 #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \
587                      PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER)
588
589 /*
590  * In order that the perf.data file is parsable, tracking events like MMAP need
591  * their selected event to exist, except if there is only 1 selected event left
592  * and it has a compatible sample type.
593  */
594 static bool ok_to_remove(struct evlist *evlist,
595                          struct evsel *evsel_to_remove)
596 {
597         struct evsel *evsel;
598         int cnt = 0;
599         bool ok = false;
600
601         if (!has_tracking(evsel_to_remove))
602                 return true;
603
604         evlist__for_each_entry(evlist, evsel) {
605                 if (evsel->handler != drop_sample) {
606                         cnt += 1;
607                         if ((evsel->core.attr.sample_type & COMPAT_MASK) ==
608                             (evsel_to_remove->core.attr.sample_type & COMPAT_MASK))
609                                 ok = true;
610                 }
611         }
612
613         return ok && cnt == 1;
614 }
615
616 static void strip_fini(struct perf_inject *inject)
617 {
618         struct evlist *evlist = inject->session->evlist;
619         struct evsel *evsel, *tmp;
620
621         /* Remove non-synthesized evsels if possible */
622         evlist__for_each_entry_safe(evlist, tmp, evsel) {
623                 if (evsel->handler == drop_sample &&
624                     ok_to_remove(evlist, evsel)) {
625                         pr_debug("Deleting %s\n", perf_evsel__name(evsel));
626                         evlist__remove(evlist, evsel);
627                         evsel__delete(evsel);
628                 }
629         }
630 }
631
632 static int __cmd_inject(struct perf_inject *inject)
633 {
634         int ret = -EINVAL;
635         struct perf_session *session = inject->session;
636         struct perf_data *data_out = &inject->output;
637         int fd = perf_data__fd(data_out);
638         u64 output_data_offset;
639
640         signal(SIGINT, sig_handler);
641
642         if (inject->build_ids || inject->sched_stat ||
643             inject->itrace_synth_opts.set) {
644                 inject->tool.mmap         = perf_event__repipe_mmap;
645                 inject->tool.mmap2        = perf_event__repipe_mmap2;
646                 inject->tool.fork         = perf_event__repipe_fork;
647                 inject->tool.tracing_data = perf_event__repipe_tracing_data;
648         }
649
650         output_data_offset = session->header.data_offset;
651
652         if (inject->build_ids) {
653                 inject->tool.sample = perf_event__inject_buildid;
654         } else if (inject->sched_stat) {
655                 struct evsel *evsel;
656
657                 evlist__for_each_entry(session->evlist, evsel) {
658                         const char *name = perf_evsel__name(evsel);
659
660                         if (!strcmp(name, "sched:sched_switch")) {
661                                 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
662                                         return -EINVAL;
663
664                                 evsel->handler = perf_inject__sched_switch;
665                         } else if (!strcmp(name, "sched:sched_process_exit"))
666                                 evsel->handler = perf_inject__sched_process_exit;
667                         else if (!strncmp(name, "sched:sched_stat_", 17))
668                                 evsel->handler = perf_inject__sched_stat;
669                 }
670         } else if (inject->itrace_synth_opts.set) {
671                 session->itrace_synth_opts = &inject->itrace_synth_opts;
672                 inject->itrace_synth_opts.inject = true;
673                 inject->tool.comm           = perf_event__repipe_comm;
674                 inject->tool.namespaces     = perf_event__repipe_namespaces;
675                 inject->tool.exit           = perf_event__repipe_exit;
676                 inject->tool.id_index       = perf_event__repipe_id_index;
677                 inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
678                 inject->tool.auxtrace       = perf_event__process_auxtrace;
679                 inject->tool.aux            = perf_event__drop_aux;
680                 inject->tool.itrace_start   = perf_event__drop_aux,
681                 inject->tool.ordered_events = true;
682                 inject->tool.ordering_requires_timestamps = true;
683                 /* Allow space in the header for new attributes */
684                 output_data_offset = 4096;
685                 if (inject->strip)
686                         strip_init(inject);
687         }
688
689         if (!inject->itrace_synth_opts.set)
690                 auxtrace_index__free(&session->auxtrace_index);
691
692         if (!data_out->is_pipe)
693                 lseek(fd, output_data_offset, SEEK_SET);
694
695         ret = perf_session__process_events(session);
696         if (ret)
697                 return ret;
698
699         if (!data_out->is_pipe) {
700                 if (inject->build_ids)
701                         perf_header__set_feat(&session->header,
702                                               HEADER_BUILD_ID);
703                 /*
704                  * Keep all buildids when there is unprocessed AUX data because
705                  * it is not known which ones the AUX trace hits.
706                  */
707                 if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
708                     inject->have_auxtrace && !inject->itrace_synth_opts.set)
709                         dsos__hit_all(session);
710                 /*
711                  * The AUX areas have been removed and replaced with
712                  * synthesized hardware events, so clear the feature flag and
713                  * remove the evsel.
714                  */
715                 if (inject->itrace_synth_opts.set) {
716                         struct evsel *evsel;
717
718                         perf_header__clear_feat(&session->header,
719                                                 HEADER_AUXTRACE);
720                         if (inject->itrace_synth_opts.last_branch)
721                                 perf_header__set_feat(&session->header,
722                                                       HEADER_BRANCH_STACK);
723                         evsel = perf_evlist__id2evsel_strict(session->evlist,
724                                                              inject->aux_id);
725                         if (evsel) {
726                                 pr_debug("Deleting %s\n",
727                                          perf_evsel__name(evsel));
728                                 evlist__remove(session->evlist, evsel);
729                                 evsel__delete(evsel);
730                         }
731                         if (inject->strip)
732                                 strip_fini(inject);
733                 }
734                 session->header.data_offset = output_data_offset;
735                 session->header.data_size = inject->bytes_written;
736                 perf_session__write_header(session, session->evlist, fd, true);
737         }
738
739         return ret;
740 }
741
742 int cmd_inject(int argc, const char **argv)
743 {
744         struct perf_inject inject = {
745                 .tool = {
746                         .sample         = perf_event__repipe_sample,
747                         .mmap           = perf_event__repipe,
748                         .mmap2          = perf_event__repipe,
749                         .comm           = perf_event__repipe,
750                         .fork           = perf_event__repipe,
751                         .exit           = perf_event__repipe,
752                         .lost           = perf_event__repipe,
753                         .lost_samples   = perf_event__repipe,
754                         .aux            = perf_event__repipe,
755                         .itrace_start   = perf_event__repipe,
756                         .context_switch = perf_event__repipe,
757                         .read           = perf_event__repipe_sample,
758                         .throttle       = perf_event__repipe,
759                         .unthrottle     = perf_event__repipe,
760                         .attr           = perf_event__repipe_attr,
761                         .tracing_data   = perf_event__repipe_op2_synth,
762                         .auxtrace_info  = perf_event__repipe_op2_synth,
763                         .auxtrace       = perf_event__repipe_auxtrace,
764                         .auxtrace_error = perf_event__repipe_op2_synth,
765                         .time_conv      = perf_event__repipe_op2_synth,
766                         .finished_round = perf_event__repipe_oe_synth,
767                         .build_id       = perf_event__repipe_op2_synth,
768                         .id_index       = perf_event__repipe_op2_synth,
769                         .feature        = perf_event__repipe_op2_synth,
770                 },
771                 .input_name  = "-",
772                 .samples = LIST_HEAD_INIT(inject.samples),
773                 .output = {
774                         .path = "-",
775                         .mode = PERF_DATA_MODE_WRITE,
776                 },
777         };
778         struct perf_data data = {
779                 .mode = PERF_DATA_MODE_READ,
780         };
781         int ret;
782
783         struct option options[] = {
784                 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
785                             "Inject build-ids into the output stream"),
786                 OPT_STRING('i', "input", &inject.input_name, "file",
787                            "input file name"),
788                 OPT_STRING('o', "output", &inject.output.path, "file",
789                            "output file name"),
790                 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
791                             "Merge sched-stat and sched-switch for getting events "
792                             "where and how long tasks slept"),
793 #ifdef HAVE_JITDUMP
794                 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
795 #endif
796                 OPT_INCR('v', "verbose", &verbose,
797                          "be more verbose (show build ids, etc)"),
798                 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
799                            "kallsyms pathname"),
800                 OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
801                 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
802                                     NULL, "opts", "Instruction Tracing options\n"
803                                     ITRACE_HELP,
804                                     itrace_parse_synth_opts),
805                 OPT_BOOLEAN(0, "strip", &inject.strip,
806                             "strip non-synthesized events (use with --itrace)"),
807                 OPT_END()
808         };
809         const char * const inject_usage[] = {
810                 "perf inject [<options>]",
811                 NULL
812         };
813 #ifndef HAVE_JITDUMP
814         set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
815 #endif
816         argc = parse_options(argc, argv, options, inject_usage, 0);
817
818         /*
819          * Any (unrecognized) arguments left?
820          */
821         if (argc)
822                 usage_with_options(inject_usage, options);
823
824         if (inject.strip && !inject.itrace_synth_opts.set) {
825                 pr_err("--strip option requires --itrace option\n");
826                 return -1;
827         }
828
829         if (perf_data__open(&inject.output)) {
830                 perror("failed to create output file");
831                 return -1;
832         }
833
834         inject.tool.ordered_events = inject.sched_stat;
835
836         data.path = inject.input_name;
837         inject.session = perf_session__new(&data, true, &inject.tool);
838         if (inject.session == NULL)
839                 return -1;
840
841         if (zstd_init(&(inject.session->zstd_data), 0) < 0)
842                 pr_warning("Decompression initialization failed.\n");
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         zstd_fini(&(inject.session->zstd_data));
875         perf_session__delete(inject.session);
876         return ret;
877 }