perf inject: Remove more aux-related stuff when processing instruction traces
[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
21 #include "util/parse-options.h"
22
23 #include <linux/list.h>
24
25 struct perf_inject {
26         struct perf_tool        tool;
27         struct perf_session     *session;
28         bool                    build_ids;
29         bool                    sched_stat;
30         bool                    have_auxtrace;
31         const char              *input_name;
32         struct perf_data_file   output;
33         u64                     bytes_written;
34         u64                     aux_id;
35         struct list_head        samples;
36         struct itrace_synth_opts itrace_synth_opts;
37 };
38
39 struct event_entry {
40         struct list_head node;
41         u32              tid;
42         union perf_event event[0];
43 };
44
45 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz)
46 {
47         ssize_t size;
48
49         size = perf_data_file__write(&inject->output, buf, sz);
50         if (size < 0)
51                 return -errno;
52
53         inject->bytes_written += size;
54         return 0;
55 }
56
57 static int perf_event__repipe_synth(struct perf_tool *tool,
58                                     union perf_event *event)
59 {
60         struct perf_inject *inject = container_of(tool, struct perf_inject,
61                                                   tool);
62
63         return output_bytes(inject, event, event->header.size);
64 }
65
66 static int perf_event__repipe_oe_synth(struct perf_tool *tool,
67                                        union perf_event *event,
68                                        struct ordered_events *oe __maybe_unused)
69 {
70         return perf_event__repipe_synth(tool, event);
71 }
72
73 static int perf_event__repipe_op2_synth(struct perf_tool *tool,
74                                         union perf_event *event,
75                                         struct perf_session *session
76                                         __maybe_unused)
77 {
78         return perf_event__repipe_synth(tool, event);
79 }
80
81 static int perf_event__repipe_attr(struct perf_tool *tool,
82                                    union perf_event *event,
83                                    struct perf_evlist **pevlist)
84 {
85         struct perf_inject *inject = container_of(tool, struct perf_inject,
86                                                   tool);
87         int ret;
88
89         ret = perf_event__process_attr(tool, event, pevlist);
90         if (ret)
91                 return ret;
92
93         if (!inject->output.is_pipe)
94                 return 0;
95
96         return perf_event__repipe_synth(tool, event);
97 }
98
99 #ifdef HAVE_AUXTRACE_SUPPORT
100
101 static int copy_bytes(struct perf_inject *inject, int fd, off_t size)
102 {
103         char buf[4096];
104         ssize_t ssz;
105         int ret;
106
107         while (size > 0) {
108                 ssz = read(fd, buf, min(size, (off_t)sizeof(buf)));
109                 if (ssz < 0)
110                         return -errno;
111                 ret = output_bytes(inject, buf, ssz);
112                 if (ret)
113                         return ret;
114                 size -= ssz;
115         }
116
117         return 0;
118 }
119
120 static s64 perf_event__repipe_auxtrace(struct perf_tool *tool,
121                                        union perf_event *event,
122                                        struct perf_session *session
123                                        __maybe_unused)
124 {
125         struct perf_inject *inject = container_of(tool, struct perf_inject,
126                                                   tool);
127         int ret;
128
129         inject->have_auxtrace = true;
130
131         if (!inject->output.is_pipe) {
132                 off_t offset;
133
134                 offset = lseek(inject->output.fd, 0, SEEK_CUR);
135                 if (offset == -1)
136                         return -errno;
137                 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index,
138                                                      event, offset);
139                 if (ret < 0)
140                         return ret;
141         }
142
143         if (perf_data_file__is_pipe(session->file) || !session->one_mmap) {
144                 ret = output_bytes(inject, event, event->header.size);
145                 if (ret < 0)
146                         return ret;
147                 ret = copy_bytes(inject, perf_data_file__fd(session->file),
148                                  event->auxtrace.size);
149         } else {
150                 ret = output_bytes(inject, event,
151                                    event->header.size + event->auxtrace.size);
152         }
153         if (ret < 0)
154                 return ret;
155
156         return event->auxtrace.size;
157 }
158
159 #else
160
161 static s64
162 perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused,
163                             union perf_event *event __maybe_unused,
164                             struct perf_session *session __maybe_unused)
165 {
166         pr_err("AUX area tracing not supported\n");
167         return -EINVAL;
168 }
169
170 #endif
171
172 static int perf_event__repipe(struct perf_tool *tool,
173                               union perf_event *event,
174                               struct perf_sample *sample __maybe_unused,
175                               struct machine *machine __maybe_unused)
176 {
177         return perf_event__repipe_synth(tool, event);
178 }
179
180 static int perf_event__drop_aux(struct perf_tool *tool,
181                                 union perf_event *event __maybe_unused,
182                                 struct perf_sample *sample,
183                                 struct machine *machine __maybe_unused)
184 {
185         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
186
187         if (!inject->aux_id)
188                 inject->aux_id = sample->id;
189
190         return 0;
191 }
192
193 typedef int (*inject_handler)(struct perf_tool *tool,
194                               union perf_event *event,
195                               struct perf_sample *sample,
196                               struct perf_evsel *evsel,
197                               struct machine *machine);
198
199 static int perf_event__repipe_sample(struct perf_tool *tool,
200                                      union perf_event *event,
201                                      struct perf_sample *sample,
202                                      struct perf_evsel *evsel,
203                                      struct machine *machine)
204 {
205         if (evsel->handler) {
206                 inject_handler f = evsel->handler;
207                 return f(tool, event, sample, evsel, machine);
208         }
209
210         build_id__mark_dso_hit(tool, event, sample, evsel, machine);
211
212         return perf_event__repipe_synth(tool, event);
213 }
214
215 static int perf_event__repipe_mmap(struct perf_tool *tool,
216                                    union perf_event *event,
217                                    struct perf_sample *sample,
218                                    struct machine *machine)
219 {
220         int err;
221
222         err = perf_event__process_mmap(tool, event, sample, machine);
223         perf_event__repipe(tool, event, sample, machine);
224
225         return err;
226 }
227
228 static int perf_event__repipe_mmap2(struct perf_tool *tool,
229                                    union perf_event *event,
230                                    struct perf_sample *sample,
231                                    struct machine *machine)
232 {
233         int err;
234
235         err = perf_event__process_mmap2(tool, event, sample, machine);
236         perf_event__repipe(tool, event, sample, machine);
237
238         return err;
239 }
240
241 static int perf_event__repipe_fork(struct perf_tool *tool,
242                                    union perf_event *event,
243                                    struct perf_sample *sample,
244                                    struct machine *machine)
245 {
246         int err;
247
248         err = perf_event__process_fork(tool, event, sample, machine);
249         perf_event__repipe(tool, event, sample, machine);
250
251         return err;
252 }
253
254 static int perf_event__repipe_comm(struct perf_tool *tool,
255                                    union perf_event *event,
256                                    struct perf_sample *sample,
257                                    struct machine *machine)
258 {
259         int err;
260
261         err = perf_event__process_comm(tool, event, sample, machine);
262         perf_event__repipe(tool, event, sample, machine);
263
264         return err;
265 }
266
267 static int perf_event__repipe_exit(struct perf_tool *tool,
268                                    union perf_event *event,
269                                    struct perf_sample *sample,
270                                    struct machine *machine)
271 {
272         int err;
273
274         err = perf_event__process_exit(tool, event, sample, machine);
275         perf_event__repipe(tool, event, sample, machine);
276
277         return err;
278 }
279
280 static int perf_event__repipe_tracing_data(struct perf_tool *tool,
281                                            union perf_event *event,
282                                            struct perf_session *session)
283 {
284         int err;
285
286         perf_event__repipe_synth(tool, event);
287         err = perf_event__process_tracing_data(tool, event, session);
288
289         return err;
290 }
291
292 static int perf_event__repipe_id_index(struct perf_tool *tool,
293                                        union perf_event *event,
294                                        struct perf_session *session)
295 {
296         int err;
297
298         perf_event__repipe_synth(tool, event);
299         err = perf_event__process_id_index(tool, event, session);
300
301         return err;
302 }
303
304 static int dso__read_build_id(struct dso *dso)
305 {
306         if (dso->has_build_id)
307                 return 0;
308
309         if (filename__read_build_id(dso->long_name, dso->build_id,
310                                     sizeof(dso->build_id)) > 0) {
311                 dso->has_build_id = true;
312                 return 0;
313         }
314
315         return -1;
316 }
317
318 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool,
319                                 struct machine *machine)
320 {
321         u16 misc = PERF_RECORD_MISC_USER;
322         int err;
323
324         if (dso__read_build_id(dso) < 0) {
325                 pr_debug("no build_id found for %s\n", dso->long_name);
326                 return -1;
327         }
328
329         if (dso->kernel)
330                 misc = PERF_RECORD_MISC_KERNEL;
331
332         err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe,
333                                               machine);
334         if (err) {
335                 pr_err("Can't synthesize build_id event for %s\n", dso->long_name);
336                 return -1;
337         }
338
339         return 0;
340 }
341
342 static int perf_event__inject_buildid(struct perf_tool *tool,
343                                       union perf_event *event,
344                                       struct perf_sample *sample,
345                                       struct perf_evsel *evsel __maybe_unused,
346                                       struct machine *machine)
347 {
348         struct addr_location al;
349         struct thread *thread;
350         u8 cpumode;
351
352         cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
353
354         thread = machine__findnew_thread(machine, sample->pid, sample->tid);
355         if (thread == NULL) {
356                 pr_err("problem processing %d event, skipping it.\n",
357                        event->header.type);
358                 goto repipe;
359         }
360
361         thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
362
363         if (al.map != NULL) {
364                 if (!al.map->dso->hit) {
365                         al.map->dso->hit = 1;
366                         if (map__load(al.map, NULL) >= 0) {
367                                 dso__inject_build_id(al.map->dso, tool, machine);
368                                 /*
369                                  * If this fails, too bad, let the other side
370                                  * account this as unresolved.
371                                  */
372                         } else {
373 #ifdef HAVE_LIBELF_SUPPORT
374                                 pr_warning("no symbols found in %s, maybe "
375                                            "install a debug package?\n",
376                                            al.map->dso->long_name);
377 #endif
378                         }
379                 }
380         }
381
382         thread__put(thread);
383 repipe:
384         perf_event__repipe(tool, event, sample, machine);
385         return 0;
386 }
387
388 static int perf_inject__sched_process_exit(struct perf_tool *tool,
389                                            union perf_event *event __maybe_unused,
390                                            struct perf_sample *sample,
391                                            struct perf_evsel *evsel __maybe_unused,
392                                            struct machine *machine __maybe_unused)
393 {
394         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
395         struct event_entry *ent;
396
397         list_for_each_entry(ent, &inject->samples, node) {
398                 if (sample->tid == ent->tid) {
399                         list_del_init(&ent->node);
400                         free(ent);
401                         break;
402                 }
403         }
404
405         return 0;
406 }
407
408 static int perf_inject__sched_switch(struct perf_tool *tool,
409                                      union perf_event *event,
410                                      struct perf_sample *sample,
411                                      struct perf_evsel *evsel,
412                                      struct machine *machine)
413 {
414         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
415         struct event_entry *ent;
416
417         perf_inject__sched_process_exit(tool, event, sample, evsel, machine);
418
419         ent = malloc(event->header.size + sizeof(struct event_entry));
420         if (ent == NULL) {
421                 color_fprintf(stderr, PERF_COLOR_RED,
422                              "Not enough memory to process sched switch event!");
423                 return -1;
424         }
425
426         ent->tid = sample->tid;
427         memcpy(&ent->event, event, event->header.size);
428         list_add(&ent->node, &inject->samples);
429         return 0;
430 }
431
432 static int perf_inject__sched_stat(struct perf_tool *tool,
433                                    union perf_event *event __maybe_unused,
434                                    struct perf_sample *sample,
435                                    struct perf_evsel *evsel,
436                                    struct machine *machine)
437 {
438         struct event_entry *ent;
439         union perf_event *event_sw;
440         struct perf_sample sample_sw;
441         struct perf_inject *inject = container_of(tool, struct perf_inject, tool);
442         u32 pid = perf_evsel__intval(evsel, sample, "pid");
443
444         list_for_each_entry(ent, &inject->samples, node) {
445                 if (pid == ent->tid)
446                         goto found;
447         }
448
449         return 0;
450 found:
451         event_sw = &ent->event[0];
452         perf_evsel__parse_sample(evsel, event_sw, &sample_sw);
453
454         sample_sw.period = sample->period;
455         sample_sw.time   = sample->time;
456         perf_event__synthesize_sample(event_sw, evsel->attr.sample_type,
457                                       evsel->attr.read_format, &sample_sw,
458                                       false);
459         build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
460         return perf_event__repipe(tool, event_sw, &sample_sw, machine);
461 }
462
463 static void sig_handler(int sig __maybe_unused)
464 {
465         session_done = 1;
466 }
467
468 static int perf_evsel__check_stype(struct perf_evsel *evsel,
469                                    u64 sample_type, const char *sample_msg)
470 {
471         struct perf_event_attr *attr = &evsel->attr;
472         const char *name = perf_evsel__name(evsel);
473
474         if (!(attr->sample_type & sample_type)) {
475                 pr_err("Samples for %s event do not have %s attribute set.",
476                         name, sample_msg);
477                 return -EINVAL;
478         }
479
480         return 0;
481 }
482
483 static int __cmd_inject(struct perf_inject *inject)
484 {
485         int ret = -EINVAL;
486         struct perf_session *session = inject->session;
487         struct perf_data_file *file_out = &inject->output;
488         int fd = perf_data_file__fd(file_out);
489         u64 output_data_offset;
490
491         signal(SIGINT, sig_handler);
492
493         if (inject->build_ids || inject->sched_stat ||
494             inject->itrace_synth_opts.set) {
495                 inject->tool.mmap         = perf_event__repipe_mmap;
496                 inject->tool.mmap2        = perf_event__repipe_mmap2;
497                 inject->tool.fork         = perf_event__repipe_fork;
498                 inject->tool.tracing_data = perf_event__repipe_tracing_data;
499         }
500
501         output_data_offset = session->header.data_offset;
502
503         if (inject->build_ids) {
504                 inject->tool.sample = perf_event__inject_buildid;
505         } else if (inject->sched_stat) {
506                 struct perf_evsel *evsel;
507
508                 evlist__for_each(session->evlist, evsel) {
509                         const char *name = perf_evsel__name(evsel);
510
511                         if (!strcmp(name, "sched:sched_switch")) {
512                                 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID"))
513                                         return -EINVAL;
514
515                                 evsel->handler = perf_inject__sched_switch;
516                         } else if (!strcmp(name, "sched:sched_process_exit"))
517                                 evsel->handler = perf_inject__sched_process_exit;
518                         else if (!strncmp(name, "sched:sched_stat_", 17))
519                                 evsel->handler = perf_inject__sched_stat;
520                 }
521         } else if (inject->itrace_synth_opts.set) {
522                 session->itrace_synth_opts = &inject->itrace_synth_opts;
523                 inject->itrace_synth_opts.inject = true;
524                 inject->tool.comm           = perf_event__repipe_comm;
525                 inject->tool.exit           = perf_event__repipe_exit;
526                 inject->tool.id_index       = perf_event__repipe_id_index;
527                 inject->tool.auxtrace_info  = perf_event__process_auxtrace_info;
528                 inject->tool.auxtrace       = perf_event__process_auxtrace;
529                 inject->tool.aux            = perf_event__drop_aux;
530                 inject->tool.itrace_start   = perf_event__drop_aux,
531                 inject->tool.ordered_events = true;
532                 inject->tool.ordering_requires_timestamps = true;
533                 /* Allow space in the header for new attributes */
534                 output_data_offset = 4096;
535         }
536
537         if (!inject->itrace_synth_opts.set)
538                 auxtrace_index__free(&session->auxtrace_index);
539
540         if (!file_out->is_pipe)
541                 lseek(fd, output_data_offset, SEEK_SET);
542
543         ret = perf_session__process_events(session);
544
545         if (!file_out->is_pipe) {
546                 if (inject->build_ids) {
547                         perf_header__set_feat(&session->header,
548                                               HEADER_BUILD_ID);
549                         if (inject->have_auxtrace)
550                                 dsos__hit_all(session);
551                 }
552                 /*
553                  * The AUX areas have been removed and replaced with
554                  * synthesized hardware events, so clear the feature flag and
555                  * remove the evsel.
556                  */
557                 if (inject->itrace_synth_opts.set) {
558                         struct perf_evsel *evsel;
559
560                         perf_header__clear_feat(&session->header,
561                                                 HEADER_AUXTRACE);
562                         if (inject->itrace_synth_opts.last_branch)
563                                 perf_header__set_feat(&session->header,
564                                                       HEADER_BRANCH_STACK);
565                         evsel = perf_evlist__id2evsel_strict(session->evlist,
566                                                              inject->aux_id);
567                         if (evsel) {
568                                 pr_debug("Deleting %s\n",
569                                          perf_evsel__name(evsel));
570                                 perf_evlist__remove(session->evlist, evsel);
571                                 perf_evsel__delete(evsel);
572                         }
573                 }
574                 session->header.data_offset = output_data_offset;
575                 session->header.data_size = inject->bytes_written;
576                 perf_session__write_header(session, session->evlist, fd, true);
577         }
578
579         return ret;
580 }
581
582 int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
583 {
584         struct perf_inject inject = {
585                 .tool = {
586                         .sample         = perf_event__repipe_sample,
587                         .mmap           = perf_event__repipe,
588                         .mmap2          = perf_event__repipe,
589                         .comm           = perf_event__repipe,
590                         .fork           = perf_event__repipe,
591                         .exit           = perf_event__repipe,
592                         .lost           = perf_event__repipe,
593                         .aux            = perf_event__repipe,
594                         .itrace_start   = perf_event__repipe,
595                         .context_switch = perf_event__repipe,
596                         .read           = perf_event__repipe_sample,
597                         .throttle       = perf_event__repipe,
598                         .unthrottle     = perf_event__repipe,
599                         .attr           = perf_event__repipe_attr,
600                         .tracing_data   = perf_event__repipe_op2_synth,
601                         .auxtrace_info  = perf_event__repipe_op2_synth,
602                         .auxtrace       = perf_event__repipe_auxtrace,
603                         .auxtrace_error = perf_event__repipe_op2_synth,
604                         .finished_round = perf_event__repipe_oe_synth,
605                         .build_id       = perf_event__repipe_op2_synth,
606                         .id_index       = perf_event__repipe_op2_synth,
607                 },
608                 .input_name  = "-",
609                 .samples = LIST_HEAD_INIT(inject.samples),
610                 .output = {
611                         .path = "-",
612                         .mode = PERF_DATA_MODE_WRITE,
613                 },
614         };
615         struct perf_data_file file = {
616                 .mode = PERF_DATA_MODE_READ,
617         };
618         int ret;
619
620         const struct option options[] = {
621                 OPT_BOOLEAN('b', "build-ids", &inject.build_ids,
622                             "Inject build-ids into the output stream"),
623                 OPT_STRING('i', "input", &inject.input_name, "file",
624                            "input file name"),
625                 OPT_STRING('o', "output", &inject.output.path, "file",
626                            "output file name"),
627                 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat,
628                             "Merge sched-stat and sched-switch for getting events "
629                             "where and how long tasks slept"),
630                 OPT_INCR('v', "verbose", &verbose,
631                          "be more verbose (show build ids, etc)"),
632                 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file",
633                            "kallsyms pathname"),
634                 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"),
635                 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts,
636                                     NULL, "opts", "Instruction Tracing options",
637                                     itrace_parse_synth_opts),
638                 OPT_END()
639         };
640         const char * const inject_usage[] = {
641                 "perf inject [<options>]",
642                 NULL
643         };
644
645         argc = parse_options(argc, argv, options, inject_usage, 0);
646
647         /*
648          * Any (unrecognized) arguments left?
649          */
650         if (argc)
651                 usage_with_options(inject_usage, options);
652
653         if (perf_data_file__open(&inject.output)) {
654                 perror("failed to create output file");
655                 return -1;
656         }
657
658         inject.tool.ordered_events = inject.sched_stat;
659
660         file.path = inject.input_name;
661         inject.session = perf_session__new(&file, true, &inject.tool);
662         if (inject.session == NULL)
663                 return -1;
664
665         ret = symbol__init(&inject.session->header.env);
666         if (ret < 0)
667                 goto out_delete;
668
669         ret = __cmd_inject(&inject);
670
671 out_delete:
672         perf_session__delete(inject.session);
673         return ret;
674 }