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