~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/perf/builtin-inject.c

Version: ~ [ linux-5.15-rc1 ] ~ [ linux-5.14.5 ] ~ [ linux-5.13.18 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.66 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.147 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.206 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.246 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.282 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.283 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp