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

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

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

~ [ 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