OSDN Git Service

Merge tag 'perf-tools-for-v5.18-2022-03-26' of git://git.kernel.org/pub/scm/linux...
[uclinux-h8/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/vdso.h"
14 #include "util/evlist.h"
15 #include "util/evsel.h"
16 #include "util/map.h"
17 #include "util/session.h"
18 #include "util/tool.h"
19 #include "util/debug.h"
20 #include "util/build-id.h"
21 #include "util/data.h"
22 #include "util/auxtrace.h"
23 #include "util/jit.h"
24 #include "util/symbol.h"
25 #include "util/synthetic-events.h"
26 #include "util/thread.h"
27 #include "util/namespaces.h"
28 #include "util/util.h"
29
30 #include <linux/err.h>
31 #include <subcmd/parse-options.h>
32 #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
33
34 #include <linux/list.h>
35 #include <linux/string.h>
36 #include <errno.h>
37 #include <signal.h>
38
39 struct perf_inject {
40         struct perf_tool        tool;
41         struct perf_session     *session;
42         bool                    build_ids;
43         bool                    build_id_all;
44         bool                    sched_stat;
45         bool                    have_auxtrace;
46         bool                    strip;
47         bool                    jit_mode;
48         bool                    in_place_update;
49         bool                    in_place_update_dry_run;
50         bool                    is_pipe;
51         const char              *input_name;
52         struct perf_data        output;
53         u64                     bytes_written;
54         u64                     aux_id;
55         struct list_head        samples;
56         struct itrace_synth_opts itrace_synth_opts;
57         char                    event_copy[PERF_SAMPLE_MAX_SIZE];
58 };
59
60 struct event_entry {
61         struct list_head node;
62         u32              tid;
63         union perf_event event[];
64 };
65
66 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
67                                 struct machine *machine, u8 cpumode, u32 flags);
68
69 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
70 {
71         ssize_t size;
72
73         size = perf_data__write(&inject->output, buf, sz);
74         if (size < 0)
75                 return -errno;
76
77         inject->bytes_written += size;
78         return 0;
79 }
80
81 static int perf_event__repipe_synth(struct perf_tool *tool,
82                                     union perf_event *event)
83 {
84         struct perf_inject *inject = container_of(tool, struct perf_inject,
85                                                   tool);
86
87         return output_bytes(inject, event, event->header.size);
88 }
89
90 static int perf_event__repipe_oe_synth(struct perf_tool *tool,
91                                        union perf_event *event,
92                                        struct ordered_events *oe __maybe_unused)
93 {
94         return perf_event__repipe_synth(tool, event);
95 }
96
97 #ifdef HAVE_JITDUMP
98 static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused,
99                                union perf_event *event __maybe_unused,
100                                struct ordered_events *oe __maybe_unused)
101 {
102         return 0;
103 }
104 #endif
105
106 static int perf_event__repipe_op2_synth(struct perf_session *session,
107                                         union perf_event *event)
108 {
109         return perf_event__repipe_synth(session->tool, event);
110 }
111
112 static int perf_event__repipe_op4_synth(struct perf_session *session,
113                                         union perf_event *event,
114                                         u64 data __maybe_unused,
115                                         const char *str __maybe_unused)
116 {
117         return perf_event__repipe_synth(session->tool, event);
118 }
119
120 static int perf_event__repipe_attr(struct perf_tool *tool,
121                                    union perf_event *event,
122                                    struct evlist **pevlist)
123 {
124         struct perf_inject *inject = container_of(tool, struct perf_inject,
125                                                   tool);
126         int ret;
127
128         ret = perf_event__process_attr(tool, event, pevlist);
129         if (ret)
130                 return ret;
131
132         if (!inject->is_pipe)
133                 return 0;
134
135         return perf_event__repipe_synth(tool, event);
136 }
137
138 static int perf_event__repipe_event_update(struct perf_tool *tool,
139                                            union perf_event *event,
140                                            struct evlist **pevlist __maybe_unused)
141 {
142         return perf_event__repipe_synth(tool, event);
143 }
144
145 #ifdef HAVE_AUXTRACE_SUPPORT
146
147 static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
148 {
149         char buf[4096];
150         ssize_t ssz;
151         int ret;
152
153         while (size > 0) {
154                 ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
155                 if (ssz < 0)
156                         return -errno;
157                 ret = output_bytes(inject, buf, ssz);
158                 if (ret)
159                         return ret;
160                 size -= ssz;
161         }
162
163         return 0;
164 }
165
166 static s64 perf_event__repipe_auxtrace(struct perf_session *session,
167                                        union perf_event *event)
168 {
169         struct perf_tool *tool = session->tool;
170         struct perf_inject *inject = container_of(tool, struct perf_inject,
171                                                   tool);
172         int ret;
173
174         inject->have_auxtrace = true;
175
176         if (!inject->output.is_pipe) {
177                 off_t offset;
178
179                 offset = lseek(inject->output.file.fd, 0, SEEK_CUR);
180                 if (offset == -1)
181                         return -errno;
182                 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
183                                                      event, offset);
184                 if (ret < 0)
185                         return ret;
186         }
187
188         if (perf_data__is_pipe(session->data) || !session->one_mmap) {
189                 ret = output_bytes(inject, event, event->header.size);
190                 if (ret < 0)
191                         return ret;
192                 ret = copy_bytes(inject, perf_data__fd(session->data),
193                                  event->auxtrace.size);
194         } else {
195                 ret = output_bytes(inject, event,
196                                    event->header.size + event->auxtrace.size);
197         }
198         if (ret < 0)
199                 return ret;
200
201         return event->auxtrace.size;
202 }
203
204 #else
205
206 static s64
207 perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused,
208                             union perf_event *event __maybe_unused)
209 {
210         pr_err("AUX area tracing not supported\n");
211         return -EINVAL;
212 }
213
214 #endif
215
216 static int perf_event__repipe(struct perf_tool *tool,
217                               union perf_event *event,
218                               struct perf_sample *sample __maybe_unused,
219                               struct machine *machine __maybe_unused)
220 {
221         return perf_event__repipe_synth(tool, event);
222 }
223
224 static int perf_event__drop(struct perf_tool *tool __maybe_unused,
225                             union perf_event *event __maybe_unused,
226                             struct perf_sample *sample __maybe_unused,
227                             struct machine *machine __maybe_unused)
228 {
229         return 0;
230 }
231
232 static int perf_event__drop_aux(struct perf_tool *tool,
233                                 union perf_event *event __maybe_unused,
234                                 struct perf_sample *sample,
235                                 struct machine *machine __maybe_unused)
236 {
237         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
238
239         if (!inject->aux_id)
240                 inject->aux_id = sample->id;
241
242         return 0;
243 }
244
245 static union perf_event *
246 perf_inject__cut_auxtrace_sample(struct perf_inject *inject,
247                                  union perf_event *event,
248                                  struct perf_sample *sample)
249 {
250         size_t sz1 = sample->aux_sample.data - (void *)event;
251         size_t sz2 = event->header.size - sample->aux_sample.size - sz1;
252         union perf_event *ev = (union perf_event *)inject->event_copy;
253
254         if (sz1 > event->header.size || sz2 > event->header.size ||
255             sz1 + sz2 > event->header.size ||
256             sz1 < sizeof(struct perf_event_header) + sizeof(u64))
257                 return event;
258
259         memcpy(ev, event, sz1);
260         memcpy((void *)ev + sz1, (void *)event + event->header.size - sz2, sz2);
261         ev->header.size = sz1 + sz2;
262         ((u64 *)((void *)ev + sz1))[-1] = 0;
263
264         return ev;
265 }
266
267 typedef int (*inject_handler)(struct perf_tool *tool,
268                               union perf_event *event,
269                               struct perf_sample *sample,
270                               struct evsel *evsel,
271                               struct machine *machine);
272
273 static int perf_event__repipe_sample(struct perf_tool *tool,
274                                      union perf_event *event,
275                                      struct perf_sample *sample,
276                                      struct evsel *evsel,
277                                      struct machine *machine)
278 {
279         struct perf_inject *inject = container_of(tool, struct perf_inject,
280                                                   tool);
281
282         if (evsel && evsel->handler) {
283                 inject_handler f = evsel->handler;
284                 return f(tool, event, sample, evsel, machine);
285         }
286
287         build_id__mark_dso_hit(tool, event, sample, evsel, machine);
288
289         if (inject->itrace_synth_opts.set && sample->aux_sample.size)
290                 event = perf_inject__cut_auxtrace_sample(inject, event, sample);
291
292         return perf_event__repipe_synth(tool, event);
293 }
294
295 static int perf_event__repipe_mmap(struct perf_tool *tool,
296                                    union perf_event *event,
297                                    struct perf_sample *sample,
298                                    struct machine *machine)
299 {
300         int err;
301
302         err = perf_event__process_mmap(tool, event, sample, machine);
303         perf_event__repipe(tool, event, sample, machine);
304
305         return err;
306 }
307
308 #ifdef HAVE_JITDUMP
309 static int perf_event__jit_repipe_mmap(struct perf_tool *tool,
310                                        union perf_event *event,
311                                        struct perf_sample *sample,
312                                        struct machine *machine)
313 {
314         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
315         u64 n = 0;
316         int ret;
317
318         /*
319          * if jit marker, then inject jit mmaps and generate ELF images
320          */
321         ret = jit_process(inject->session, &inject->output, machine,
322                           event->mmap.filename, event->mmap.pid, event->mmap.tid, &n);
323         if (ret < 0)
324                 return ret;
325         if (ret) {
326                 inject->bytes_written += n;
327                 return 0;
328         }
329         return perf_event__repipe_mmap(tool, event, sample, machine);
330 }
331 #endif
332
333 static struct dso *findnew_dso(int pid, int tid, const char *filename,
334                                struct dso_id *id, struct machine *machine)
335 {
336         struct thread *thread;
337         struct nsinfo *nsi = NULL;
338         struct nsinfo *nnsi;
339         struct dso *dso;
340         bool vdso;
341
342         thread = machine__findnew_thread(machine, pid, tid);
343         if (thread == NULL) {
344                 pr_err("cannot find or create a task %d/%d.\n", tid, pid);
345                 return NULL;
346         }
347
348         vdso = is_vdso_map(filename);
349         nsi = nsinfo__get(thread->nsinfo);
350
351         if (vdso) {
352                 /* The vdso maps are always on the host and not the
353                  * container.  Ensure that we don't use setns to look
354                  * them up.
355                  */
356                 nnsi = nsinfo__copy(nsi);
357                 if (nnsi) {
358                         nsinfo__put(nsi);
359                         nsinfo__clear_need_setns(nnsi);
360                         nsi = nnsi;
361                 }
362                 dso = machine__findnew_vdso(machine, thread);
363         } else {
364                 dso = machine__findnew_dso_id(machine, filename, id);
365         }
366
367         if (dso) {
368                 nsinfo__put(dso->nsinfo);
369                 dso->nsinfo = nsi;
370         } else
371                 nsinfo__put(nsi);
372
373         thread__put(thread);
374         return dso;
375 }
376
377 static int perf_event__repipe_buildid_mmap(struct perf_tool *tool,
378                                            union perf_event *event,
379                                            struct perf_sample *sample,
380                                            struct machine *machine)
381 {
382         struct dso *dso;
383
384         dso = findnew_dso(event->mmap.pid, event->mmap.tid,
385                           event->mmap.filename, NULL, machine);
386
387         if (dso && !dso->hit) {
388                 dso->hit = 1;
389                 dso__inject_build_id(dso, tool, machine, sample->cpumode, 0);
390         }
391         dso__put(dso);
392
393         return perf_event__repipe(tool, event, sample, machine);
394 }
395
396 static int perf_event__repipe_mmap2(struct perf_tool *tool,
397                                    union perf_event *event,
398                                    struct perf_sample *sample,
399                                    struct machine *machine)
400 {
401         int err;
402
403         err = perf_event__process_mmap2(tool, event, sample, machine);
404         perf_event__repipe(tool, event, sample, machine);
405
406         if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
407                 struct dso *dso;
408
409                 dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
410                                   event->mmap2.filename, NULL, machine);
411                 if (dso) {
412                         /* mark it not to inject build-id */
413                         dso->hit = 1;
414                 }
415                 dso__put(dso);
416         }
417
418         return err;
419 }
420
421 #ifdef HAVE_JITDUMP
422 static int perf_event__jit_repipe_mmap2(struct perf_tool *tool,
423                                         union perf_event *event,
424                                         struct perf_sample *sample,
425                                         struct machine *machine)
426 {
427         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
428         u64 n = 0;
429         int ret;
430
431         /*
432          * if jit marker, then inject jit mmaps and generate ELF images
433          */
434         ret = jit_process(inject->session, &inject->output, machine,
435                           event->mmap2.filename, event->mmap2.pid, event->mmap2.tid, &n);
436         if (ret < 0)
437                 return ret;
438         if (ret) {
439                 inject->bytes_written += n;
440                 return 0;
441         }
442         return perf_event__repipe_mmap2(tool, event, sample, machine);
443 }
444 #endif
445
446 static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool,
447                                             union perf_event *event,
448                                             struct perf_sample *sample,
449                                             struct machine *machine)
450 {
451         struct dso_id dso_id = {
452                 .maj = event->mmap2.maj,
453                 .min = event->mmap2.min,
454                 .ino = event->mmap2.ino,
455                 .ino_generation = event->mmap2.ino_generation,
456         };
457         struct dso *dso;
458
459         if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) {
460                 /* cannot use dso_id since it'd have invalid info */
461                 dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
462                                   event->mmap2.filename, NULL, machine);
463                 if (dso) {
464                         /* mark it not to inject build-id */
465                         dso->hit = 1;
466                 }
467                 dso__put(dso);
468                 return 0;
469         }
470
471         dso = findnew_dso(event->mmap2.pid, event->mmap2.tid,
472                           event->mmap2.filename, &dso_id, machine);
473
474         if (dso && !dso->hit) {
475                 dso->hit = 1;
476                 dso__inject_build_id(dso, tool, machine, sample->cpumode,
477                                      event->mmap2.flags);
478         }
479         dso__put(dso);
480
481         perf_event__repipe(tool, event, sample, machine);
482
483         return 0;
484 }
485
486 static int perf_event__repipe_fork(struct perf_tool *tool,
487                                    union perf_event *event,
488                                    struct perf_sample *sample,
489                                    struct machine *machine)
490 {
491         int err;
492
493         err = perf_event__process_fork(tool, event, sample, machine);
494         perf_event__repipe(tool, event, sample, machine);
495
496         return err;
497 }
498
499 static int perf_event__repipe_comm(struct perf_tool *tool,
500                                    union perf_event *event,
501                                    struct perf_sample *sample,
502                                    struct machine *machine)
503 {
504         int err;
505
506         err = perf_event__process_comm(tool, event, sample, machine);
507         perf_event__repipe(tool, event, sample, machine);
508
509         return err;
510 }
511
512 static int perf_event__repipe_namespaces(struct perf_tool *tool,
513                                          union perf_event *event,
514                                          struct perf_sample *sample,
515                                          struct machine *machine)
516 {
517         int err = perf_event__process_namespaces(tool, event, sample, machine);
518
519         perf_event__repipe(tool, event, sample, machine);
520
521         return err;
522 }
523
524 static int perf_event__repipe_exit(struct perf_tool *tool,
525                                    union perf_event *event,
526                                    struct perf_sample *sample,
527                                    struct machine *machine)
528 {
529         int err;
530
531         err = perf_event__process_exit(tool, event, sample, machine);
532         perf_event__repipe(tool, event, sample, machine);
533
534         return err;
535 }
536
537 static int perf_event__repipe_tracing_data(struct perf_session *session,
538                                            union perf_event *event)
539 {
540         perf_event__repipe_synth(session->tool, event);
541
542         return perf_event__process_tracing_data(session, event);
543 }
544
545 static int dso__read_build_id(struct dso *dso)
546 {
547         struct nscookie nsc;
548
549         if (dso->has_build_id)
550                 return 0;
551
552         nsinfo__mountns_enter(dso->nsinfo, &nsc);
553         if (filename__read_build_id(dso->long_name, &dso->bid) > 0)
554                 dso->has_build_id = true;
555         else if (dso->nsinfo) {
556                 char *new_name;
557
558                 new_name = filename_with_chroot(dso->nsinfo->pid,
559                                                 dso->long_name);
560                 if (new_name && filename__read_build_id(new_name, &dso->bid) > 0)
561                         dso->has_build_id = true;
562                 free(new_name);
563         }
564         nsinfo__mountns_exit(&nsc);
565
566         return dso->has_build_id ? 0 : -1;
567 }
568
569 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
570                                 struct machine *machine, u8 cpumode, u32 flags)
571 {
572         int err;
573
574         if (is_anon_memory(dso->long_name) || flags & MAP_HUGETLB)
575                 return 0;
576         if (is_no_dso_memory(dso->long_name))
577                 return 0;
578
579         if (dso__read_build_id(dso) < 0) {
580                 pr_debug("no build_id found for %s\n", dso->long_name);
581                 return -1;
582         }
583
584         err = perf_event__synthesize_build_id(tool, dso, cpumode,
585                                               perf_event__repipe, machine);
586         if (err) {
587                 pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
588                 return -1;
589         }
590
591         return 0;
592 }
593
594 int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event,
595                                struct perf_sample *sample,
596                                struct evsel *evsel __maybe_unused,
597                                struct machine *machine)
598 {
599         struct addr_location al;
600         struct thread *thread;
601
602         thread = machine__findnew_thread(machine, sample->pid, sample->tid);
603         if (thread == NULL) {
604                 pr_err("problem processing %d event, skipping it.\n",
605                        event->header.type);
606                 goto repipe;
607         }
608
609         if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) {
610                 if (!al.map->dso->hit) {
611                         al.map->dso->hit = 1;
612                         dso__inject_build_id(al.map->dso, tool, machine,
613                                              sample->cpumode, al.map->flags);
614                 }
615         }
616
617         thread__put(thread);
618 repipe:
619         perf_event__repipe(tool, event, sample, machine);
620         return 0;
621 }
622
623 static int perf_inject__sched_process_exit(struct perf_tool *tool,
624                                            union perf_event *event __maybe_unused,
625                                            struct perf_sample *sample,
626                                            struct evsel *evsel __maybe_unused,
627                                            struct machine *machine __maybe_unused)
628 {
629         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
630         struct event_entry *ent;
631
632         list_for_each_entry(ent, &inject->samples, node) {
633                 if (sample->tid == ent->tid) {
634                         list_del_init(&ent->node);
635                         free(ent);
636                         break;
637                 }
638         }
639
640         return 0;
641 }
642
643 static int perf_inject__sched_switch(struct perf_tool *tool,
644                                      union perf_event *event,
645                                      struct perf_sample *sample,
646                                      struct evsel *evsel,
647                                      struct machine *machine)
648 {
649         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
650         struct event_entry *ent;
651
652         perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
653
654         ent = malloc(event->header.size + sizeof(struct event_entry));
655         if (ent == NULL) {
656                 color_fprintf(stderr, PERF_COLOR_RED,
657                              "Not enough memory to process sched switch event!");
658                 return -1;
659         }
660
661         ent->tid = sample->tid;
662         memcpy(&ent->event, event, event->header.size);
663         list_add(&ent->node, &inject->samples);
664         return 0;
665 }
666
667 static int perf_inject__sched_stat(struct perf_tool *tool,
668                                    union perf_event *event __maybe_unused,
669                                    struct perf_sample *sample,
670                                    struct evsel *evsel,
671                                    struct machine *machine)
672 {
673         struct event_entry *ent;
674         union perf_event *event_sw;
675         struct perf_sample sample_sw;
676         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
677         u32 pid = evsel__intval(evsel, sample, "pid");
678
679         list_for_each_entry(ent, &inject->samples, node) {
680                 if (pid == ent->tid)
681                         goto found;
682         }
683
684         return 0;
685 found:
686         event_sw = &ent->event[0];
687         evsel__parse_sample(evsel, event_sw, &sample_sw);
688
689         sample_sw.period = sample->period;
690         sample_sw.time   = sample->time;
691         perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type,
692                                       evsel->core.attr.read_format, &sample_sw);
693         build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
694         return perf_event__repipe(tool, event_sw, &sample_sw, machine);
695 }
696
697 static void sig_handler(int sig __maybe_unused)
698 {
699         session_done = 1;
700 }
701
702 static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg)
703 {
704         struct perf_event_attr *attr = &evsel->core.attr;
705         const char *name = evsel__name(evsel);
706
707         if (!(attr->sample_type & sample_type)) {
708                 pr_err("Samples for %s event do not have %s attribute set.",
709                         name, sample_msg);
710                 return -EINVAL;
711         }
712
713         return 0;
714 }
715
716 static int drop_sample(struct perf_tool *tool __maybe_unused,
717                        union perf_event *event __maybe_unused,
718                        struct perf_sample *sample __maybe_unused,
719                        struct evsel *evsel __maybe_unused,
720                        struct machine *machine __maybe_unused)
721 {
722         return 0;
723 }
724
725 static void strip_init(struct perf_inject *inject)
726 {
727         struct evlist *evlist = inject->session->evlist;
728         struct evsel *evsel;
729
730         inject->tool.context_switch = perf_event__drop;
731
732         evlist__for_each_entry(evlist, evsel)
733                 evsel->handler = drop_sample;
734 }
735
736 static int parse_vm_time_correlation(const struct option *opt, const char *str, int unset)
737 {
738         struct perf_inject *inject = opt->value;
739         const char *args;
740         char *dry_run;
741
742         if (unset)
743                 return 0;
744
745         inject->itrace_synth_opts.set = true;
746         inject->itrace_synth_opts.vm_time_correlation = true;
747         inject->in_place_update = true;
748
749         if (!str)
750                 return 0;
751
752         dry_run = skip_spaces(str);
753         if (!strncmp(dry_run, "dry-run", strlen("dry-run"))) {
754                 inject->itrace_synth_opts.vm_tm_corr_dry_run = true;
755                 inject->in_place_update_dry_run = true;
756                 args = dry_run + strlen("dry-run");
757         } else {
758                 args = str;
759         }
760
761         inject->itrace_synth_opts.vm_tm_corr_args = strdup(args);
762
763         return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM;
764 }
765
766 static int output_fd(struct perf_inject *inject)
767 {
768         return inject->in_place_update ? -1 : perf_data__fd(&inject->output);
769 }
770
771 static int __cmd_inject(struct perf_inject *inject)
772 {
773         int ret = -EINVAL;
774         struct perf_session *session = inject->session;
775         int fd = output_fd(inject);
776         u64 output_data_offset;
777
778         signal(SIGINT, sig_handler);
779
780         if (inject->build_ids || inject->sched_stat ||
781             inject->itrace_synth_opts.set || inject->build_id_all) {
782                 inject->tool.mmap         = perf_event__repipe_mmap;
783                 inject->tool.mmap2        = perf_event__repipe_mmap2;
784                 inject->tool.fork         = perf_event__repipe_fork;
785                 inject->tool.tracing_data = perf_event__repipe_tracing_data;
786         }
787
788         output_data_offset = session->header.data_offset;
789
790         if (inject->build_id_all) {
791                 inject->tool.mmap         = perf_event__repipe_buildid_mmap;
792                 inject->tool.mmap2        = perf_event__repipe_buildid_mmap2;
793         } else if (inject->build_ids) {
794                 inject->tool.sample = perf_event__inject_buildid;
795         } else if (inject->sched_stat) {
796                 struct evsel *evsel;
797
798                 evlist__for_each_entry(session->evlist, evsel) {
799                         const char *name = evsel__name(evsel);
800
801                         if (!strcmp(name, "sched:sched_switch")) {
802                                 if (evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
803                                         return -EINVAL;
804
805                                 evsel->handler = perf_inject__sched_switch;
806                         } else if (!strcmp(name, "sched:sched_process_exit"))
807                                 evsel->handler = perf_inject__sched_process_exit;
808                         else if (!strncmp(name, "sched:sched_stat_", 17))
809                                 evsel->handler = perf_inject__sched_stat;
810                 }
811         } else if (inject->itrace_synth_opts.vm_time_correlation) {
812                 session->itrace_synth_opts = &inject->itrace_synth_opts;
813                 memset(&inject->tool, 0, sizeof(inject->tool));
814                 inject->tool.id_index       = perf_event__process_id_index;
815                 inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
816                 inject->tool.auxtrace       = perf_event__process_auxtrace;
817                 inject->tool.auxtrace_error = perf_event__process_auxtrace_error;
818                 inject->tool.ordered_events = true;
819                 inject->tool.ordering_requires_timestamps = true;
820         } else if (inject->itrace_synth_opts.set) {
821                 session->itrace_synth_opts = &inject->itrace_synth_opts;
822                 inject->itrace_synth_opts.inject = true;
823                 inject->tool.comm           = perf_event__repipe_comm;
824                 inject->tool.namespaces     = perf_event__repipe_namespaces;
825                 inject->tool.exit           = perf_event__repipe_exit;
826                 inject->tool.id_index       = perf_event__process_id_index;
827                 inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
828                 inject->tool.auxtrace       = perf_event__process_auxtrace;
829                 inject->tool.aux            = perf_event__drop_aux;
830                 inject->tool.itrace_start   = perf_event__drop_aux;
831                 inject->tool.aux_output_hw_id = perf_event__drop_aux;
832                 inject->tool.ordered_events = true;
833                 inject->tool.ordering_requires_timestamps = true;
834                 /* Allow space in the header for new attributes */
835                 output_data_offset = roundup(8192 + session->header.data_offset, 4096);
836                 if (inject->strip)
837                         strip_init(inject);
838         }
839
840         if (!inject->itrace_synth_opts.set)
841                 auxtrace_index__free(&session->auxtrace_index);
842
843         if (!inject->is_pipe && !inject->in_place_update)
844                 lseek(fd, output_data_offset, SEEK_SET);
845
846         ret = perf_session__process_events(session);
847         if (ret)
848                 return ret;
849
850         if (!inject->is_pipe && !inject->in_place_update) {
851                 if (inject->build_ids)
852                         perf_header__set_feat(&session->header,
853                                               HEADER_BUILD_ID);
854                 /*
855                  * Keep all buildids when there is unprocessed AUX data because
856                  * it is not known which ones the AUX trace hits.
857                  */
858                 if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) &&
859                     inject->have_auxtrace && !inject->itrace_synth_opts.set)
860                         dsos__hit_all(session);
861                 /*
862                  * The AUX areas have been removed and replaced with
863                  * synthesized hardware events, so clear the feature flag.
864                  */
865                 if (inject->itrace_synth_opts.set) {
866                         perf_header__clear_feat(&session->header,
867                                                 HEADER_AUXTRACE);
868                         if (inject->itrace_synth_opts.last_branch ||
869                             inject->itrace_synth_opts.add_last_branch)
870                                 perf_header__set_feat(&session->header,
871                                                       HEADER_BRANCH_STACK);
872                 }
873                 session->header.data_offset = output_data_offset;
874                 session->header.data_size = inject->bytes_written;
875                 perf_session__write_header(session, session->evlist, fd, true);
876         }
877
878         return ret;
879 }
880
881 int cmd_inject(int argc, const char **argv)
882 {
883         struct perf_inject inject = {
884                 .tool = {
885                         .sample         = perf_event__repipe_sample,
886                         .read           = perf_event__repipe_sample,
887                         .mmap           = perf_event__repipe,
888                         .mmap2          = perf_event__repipe,
889                         .comm           = perf_event__repipe,
890                         .namespaces     = perf_event__repipe,
891                         .cgroup         = perf_event__repipe,
892                         .fork           = perf_event__repipe,
893                         .exit           = perf_event__repipe,
894                         .lost           = perf_event__repipe,
895                         .lost_samples   = perf_event__repipe,
896                         .aux            = perf_event__repipe,
897                         .itrace_start   = perf_event__repipe,
898                         .aux_output_hw_id = perf_event__repipe,
899                         .context_switch = perf_event__repipe,
900                         .throttle       = perf_event__repipe,
901                         .unthrottle     = perf_event__repipe,
902                         .ksymbol        = perf_event__repipe,
903                         .bpf            = perf_event__repipe,
904                         .text_poke      = perf_event__repipe,
905                         .attr           = perf_event__repipe_attr,
906                         .event_update   = perf_event__repipe_event_update,
907                         .tracing_data   = perf_event__repipe_op2_synth,
908                         .finished_round = perf_event__repipe_oe_synth,
909                         .build_id       = perf_event__repipe_op2_synth,
910                         .id_index       = perf_event__repipe_op2_synth,
911                         .auxtrace_info  = perf_event__repipe_op2_synth,
912                         .auxtrace_error = perf_event__repipe_op2_synth,
913                         .time_conv      = perf_event__repipe_op2_synth,
914                         .thread_map     = perf_event__repipe_op2_synth,
915                         .cpu_map        = perf_event__repipe_op2_synth,
916                         .stat_config    = perf_event__repipe_op2_synth,
917                         .stat           = perf_event__repipe_op2_synth,
918                         .stat_round     = perf_event__repipe_op2_synth,
919                         .feature        = perf_event__repipe_op2_synth,
920                         .compressed     = perf_event__repipe_op4_synth,
921                         .auxtrace       = perf_event__repipe_auxtrace,
922                 },
923                 .input_name  = "-",
924                 .samples = LIST_HEAD_INIT(inject.samples),
925                 .output = {
926                         .path = "-",
927                         .mode = PERF_DATA_MODE_WRITE,
928                         .use_stdio = true,
929                 },
930         };
931         struct perf_data data = {
932                 .mode = PERF_DATA_MODE_READ,
933                 .use_stdio = true,
934         };
935         int ret;
936         bool repipe = true;
937
938         struct option options[] = {
939                 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
940                             "Inject build-ids into the output stream"),
941                 OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all,
942                             "Inject build-ids of all DSOs into the output stream"),
943                 OPT_STRING('i', "input", &inject.input_name, "file",
944                            "input file name"),
945                 OPT_STRING('o', "output", &inject.output.path, "file",
946                            "output file name"),
947                 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
948                             "Merge sched-stat and sched-switch for getting events "
949                             "where and how long tasks slept"),
950 #ifdef HAVE_JITDUMP
951                 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"),
952 #endif
953                 OPT_INCR('v', "verbose", &verbose,
954                          "be more verbose (show build ids, etc)"),
955                 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
956                            "file", "vmlinux pathname"),
957                 OPT_BOOLEAN(0, "ignore-vmlinux", &symbol_conf.ignore_vmlinux,
958                             "don't load vmlinux even if found"),
959                 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
960                            "kallsyms pathname"),
961                 OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"),
962                 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
963                                     NULL, "opts", "Instruction Tracing options\n"
964                                     ITRACE_HELP,
965                                     itrace_parse_synth_opts),
966                 OPT_BOOLEAN(0, "strip", &inject.strip,
967                             "strip non-synthesized events (use with --itrace)"),
968                 OPT_CALLBACK_OPTARG(0, "vm-time-correlation", &inject, NULL, "opts",
969                                     "correlate time between VM guests and the host",
970                                     parse_vm_time_correlation),
971                 OPT_END()
972         };
973         const char * const inject_usage[] = {
974                 "perf inject [<options>]",
975                 NULL
976         };
977 #ifndef HAVE_JITDUMP
978         set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true);
979 #endif
980         argc = parse_options(argc, argv, options, inject_usage, 0);
981
982         /*
983          * Any (unrecognized) arguments left?
984          */
985         if (argc)
986                 usage_with_options(inject_usage, options);
987
988         if (inject.strip && !inject.itrace_synth_opts.set) {
989                 pr_err("--strip option requires --itrace option\n");
990                 return -1;
991         }
992
993         if (symbol__validate_sym_arguments())
994                 return -1;
995
996         if (inject.in_place_update) {
997                 if (!strcmp(inject.input_name, "-")) {
998                         pr_err("Input file name required for in-place updating\n");
999                         return -1;
1000                 }
1001                 if (strcmp(inject.output.path, "-")) {
1002                         pr_err("Output file name must not be specified for in-place updating\n");
1003                         return -1;
1004                 }
1005                 if (!data.force && !inject.in_place_update_dry_run) {
1006                         pr_err("The input file would be updated in place, "
1007                                 "the --force option is required.\n");
1008                         return -1;
1009                 }
1010                 if (!inject.in_place_update_dry_run)
1011                         data.in_place_update = true;
1012         } else if (perf_data__open(&inject.output)) {
1013                 perror("failed to create output file");
1014                 return -1;
1015         }
1016
1017         data.path = inject.input_name;
1018         if (!strcmp(inject.input_name, "-") || inject.output.is_pipe) {
1019                 inject.is_pipe = true;
1020                 /*
1021                  * Do not repipe header when input is a regular file
1022                  * since either it can rewrite the header at the end
1023                  * or write a new pipe header.
1024                  */
1025                 if (strcmp(inject.input_name, "-"))
1026                         repipe = false;
1027         }
1028
1029         inject.session = __perf_session__new(&data, repipe,
1030                                              output_fd(&inject),
1031                                              &inject.tool);
1032         if (IS_ERR(inject.session)) {
1033                 ret = PTR_ERR(inject.session);
1034                 goto out_close_output;
1035         }
1036
1037         if (zstd_init(&(inject.session->zstd_data), 0) < 0)
1038                 pr_warning("Decompression initialization failed.\n");
1039
1040         if (!data.is_pipe && inject.output.is_pipe) {
1041                 ret = perf_header__write_pipe(perf_data__fd(&inject.output));
1042                 if (ret < 0) {
1043                         pr_err("Couldn't write a new pipe header.\n");
1044                         goto out_delete;
1045                 }
1046
1047                 ret = perf_event__synthesize_for_pipe(&inject.tool,
1048                                                       inject.session,
1049                                                       &inject.output,
1050                                                       perf_event__repipe);
1051                 if (ret < 0)
1052                         goto out_delete;
1053         }
1054
1055         if (inject.build_ids && !inject.build_id_all) {
1056                 /*
1057                  * to make sure the mmap records are ordered correctly
1058                  * and so that the correct especially due to jitted code
1059                  * mmaps. We cannot generate the buildid hit list and
1060                  * inject the jit mmaps at the same time for now.
1061                  */
1062                 inject.tool.ordered_events = true;
1063                 inject.tool.ordering_requires_timestamps = true;
1064         }
1065
1066         if (inject.sched_stat) {
1067                 inject.tool.ordered_events = true;
1068         }
1069
1070 #ifdef HAVE_JITDUMP
1071         if (inject.jit_mode) {
1072                 inject.tool.mmap2          = perf_event__jit_repipe_mmap2;
1073                 inject.tool.mmap           = perf_event__jit_repipe_mmap;
1074                 inject.tool.ordered_events = true;
1075                 inject.tool.ordering_requires_timestamps = true;
1076                 /*
1077                  * JIT MMAP injection injects all MMAP events in one go, so it
1078                  * does not obey finished_round semantics.
1079                  */
1080                 inject.tool.finished_round = perf_event__drop_oe;
1081         }
1082 #endif
1083         ret = symbol__init(&inject.session->header.env);
1084         if (ret < 0)
1085                 goto out_delete;
1086
1087         ret = __cmd_inject(&inject);
1088
1089 out_delete:
1090         zstd_fini(&(inject.session->zstd_data));
1091         perf_session__delete(inject.session);
1092 out_close_output:
1093         if (!inject.in_place_update)
1094                 perf_data__close(&inject.output);
1095         free(inject.itrace_synth_opts.vm_tm_corr_args);
1096         return ret;
1097 }