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