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

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

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

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