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