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