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