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 if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) { 444 if (!al.map->dso->hit) { 445 al.map->dso->hit = 1; 446 if (map__load(al.map) >= 0) { 447 dso__inject_build_id(al.map->dso, tool, machine); 448 /* 449 * If this fails, too bad, let the other side 450 * account this as unresolved. 451 */ 452 } else { 453 #ifdef HAVE_LIBELF_SUPPORT 454 pr_warning("no symbols found in %s, maybe " 455 "install a debug package?\n", 456 al.map->dso->long_name); 457 #endif 458 } 459 } 460 } 461 462 thread__put(thread); 463 repipe: 464 perf_event__repipe(tool, event, sample, machine); 465 return 0; 466 } 467 468 static int perf_inject__sched_process_exit(struct perf_tool *tool, 469 union perf_event *event __maybe_unused, 470 struct perf_sample *sample, 471 struct perf_evsel *evsel __maybe_unused, 472 struct machine *machine __maybe_unused) 473 { 474 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 475 struct event_entry *ent; 476 477 list_for_each_entry(ent, &inject->samples, node) { 478 if (sample->tid == ent->tid) { 479 list_del_init(&ent->node); 480 free(ent); 481 break; 482 } 483 } 484 485 return 0; 486 } 487 488 static int perf_inject__sched_switch(struct perf_tool *tool, 489 union perf_event *event, 490 struct perf_sample *sample, 491 struct perf_evsel *evsel, 492 struct machine *machine) 493 { 494 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 495 struct event_entry *ent; 496 497 perf_inject__sched_process_exit(tool, event, sample, evsel, machine); 498 499 ent = malloc(event->header.size + sizeof(struct event_entry)); 500 if (ent == NULL) { 501 color_fprintf(stderr, PERF_COLOR_RED, 502 "Not enough memory to process sched switch event!"); 503 return -1; 504 } 505 506 ent->tid = sample->tid; 507 memcpy(&ent->event, event, event->header.size); 508 list_add(&ent->node, &inject->samples); 509 return 0; 510 } 511 512 static int perf_inject__sched_stat(struct perf_tool *tool, 513 union perf_event *event __maybe_unused, 514 struct perf_sample *sample, 515 struct perf_evsel *evsel, 516 struct machine *machine) 517 { 518 struct event_entry *ent; 519 union perf_event *event_sw; 520 struct perf_sample sample_sw; 521 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 522 u32 pid = perf_evsel__intval(evsel, sample, "pid"); 523 524 list_for_each_entry(ent, &inject->samples, node) { 525 if (pid == ent->tid) 526 goto found; 527 } 528 529 return 0; 530 found: 531 event_sw = &ent->event[0]; 532 perf_evsel__parse_sample(evsel, event_sw, &sample_sw); 533 534 sample_sw.period = sample->period; 535 sample_sw.time = sample->time; 536 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, 537 evsel->attr.read_format, &sample_sw); 538 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); 539 return perf_event__repipe(tool, event_sw, &sample_sw, machine); 540 } 541 542 static void sig_handler(int sig __maybe_unused) 543 { 544 session_done = 1; 545 } 546 547 static int perf_evsel__check_stype(struct perf_evsel *evsel, 548 u64 sample_type, const char *sample_msg) 549 { 550 struct perf_event_attr *attr = &evsel->attr; 551 const char *name = perf_evsel__name(evsel); 552 553 if (!(attr->sample_type & sample_type)) { 554 pr_err("Samples for %s event do not have %s attribute set.", 555 name, sample_msg); 556 return -EINVAL; 557 } 558 559 return 0; 560 } 561 562 static int drop_sample(struct perf_tool *tool __maybe_unused, 563 union perf_event *event __maybe_unused, 564 struct perf_sample *sample __maybe_unused, 565 struct perf_evsel *evsel __maybe_unused, 566 struct machine *machine __maybe_unused) 567 { 568 return 0; 569 } 570 571 static void strip_init(struct perf_inject *inject) 572 { 573 struct perf_evlist *evlist = inject->session->evlist; 574 struct perf_evsel *evsel; 575 576 inject->tool.context_switch = perf_event__drop; 577 578 evlist__for_each_entry(evlist, evsel) 579 evsel->handler = drop_sample; 580 } 581 582 static bool has_tracking(struct perf_evsel *evsel) 583 { 584 return evsel->attr.mmap || evsel->attr.mmap2 || evsel->attr.comm || 585 evsel->attr.task; 586 } 587 588 #define COMPAT_MASK (PERF_SAMPLE_ID | PERF_SAMPLE_TID | PERF_SAMPLE_TIME | \ 589 PERF_SAMPLE_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER) 590 591 /* 592 * In order that the perf.data file is parsable, tracking events like MMAP need 593 * their selected event to exist, except if there is only 1 selected event left 594 * and it has a compatible sample type. 595 */ 596 static bool ok_to_remove(struct perf_evlist *evlist, 597 struct perf_evsel *evsel_to_remove) 598 { 599 struct perf_evsel *evsel; 600 int cnt = 0; 601 bool ok = false; 602 603 if (!has_tracking(evsel_to_remove)) 604 return true; 605 606 evlist__for_each_entry(evlist, evsel) { 607 if (evsel->handler != drop_sample) { 608 cnt += 1; 609 if ((evsel->attr.sample_type & COMPAT_MASK) == 610 (evsel_to_remove->attr.sample_type & COMPAT_MASK)) 611 ok = true; 612 } 613 } 614 615 return ok && cnt == 1; 616 } 617 618 static void strip_fini(struct perf_inject *inject) 619 { 620 struct perf_evlist *evlist = inject->session->evlist; 621 struct perf_evsel *evsel, *tmp; 622 623 /* Remove non-synthesized evsels if possible */ 624 evlist__for_each_entry_safe(evlist, tmp, evsel) { 625 if (evsel->handler == drop_sample && 626 ok_to_remove(evlist, evsel)) { 627 pr_debug("Deleting %s\n", perf_evsel__name(evsel)); 628 perf_evlist__remove(evlist, evsel); 629 perf_evsel__delete(evsel); 630 } 631 } 632 } 633 634 static int __cmd_inject(struct perf_inject *inject) 635 { 636 int ret = -EINVAL; 637 struct perf_session *session = inject->session; 638 struct perf_data *data_out = &inject->output; 639 int fd = perf_data__fd(data_out); 640 u64 output_data_offset; 641 642 signal(SIGINT, sig_handler); 643 644 if (inject->build_ids || inject->sched_stat || 645 inject->itrace_synth_opts.set) { 646 inject->tool.mmap = perf_event__repipe_mmap; 647 inject->tool.mmap2 = perf_event__repipe_mmap2; 648 inject->tool.fork = perf_event__repipe_fork; 649 inject->tool.tracing_data = perf_event__repipe_tracing_data; 650 } 651 652 output_data_offset = session->header.data_offset; 653 654 if (inject->build_ids) { 655 inject->tool.sample = perf_event__inject_buildid; 656 } else if (inject->sched_stat) { 657 struct perf_evsel *evsel; 658 659 evlist__for_each_entry(session->evlist, evsel) { 660 const char *name = perf_evsel__name(evsel); 661 662 if (!strcmp(name, "sched:sched_switch")) { 663 if (perf_evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) 664 return -EINVAL; 665 666 evsel->handler = perf_inject__sched_switch; 667 } else if (!strcmp(name, "sched:sched_process_exit")) 668 evsel->handler = perf_inject__sched_process_exit; 669 else if (!strncmp(name, "sched:sched_stat_", 17)) 670 evsel->handler = perf_inject__sched_stat; 671 } 672 } else if (inject->itrace_synth_opts.set) { 673 session->itrace_synth_opts = &inject->itrace_synth_opts; 674 inject->itrace_synth_opts.inject = true; 675 inject->tool.comm = perf_event__repipe_comm; 676 inject->tool.namespaces = perf_event__repipe_namespaces; 677 inject->tool.exit = perf_event__repipe_exit; 678 inject->tool.id_index = perf_event__repipe_id_index; 679 inject->tool.auxtrace_info = perf_event__process_auxtrace_info; 680 inject->tool.auxtrace = perf_event__process_auxtrace; 681 inject->tool.aux = perf_event__drop_aux; 682 inject->tool.itrace_start = perf_event__drop_aux, 683 inject->tool.ordered_events = true; 684 inject->tool.ordering_requires_timestamps = true; 685 /* Allow space in the header for new attributes */ 686 output_data_offset = 4096; 687 if (inject->strip) 688 strip_init(inject); 689 } 690 691 if (!inject->itrace_synth_opts.set) 692 auxtrace_index__free(&session->auxtrace_index); 693 694 if (!data_out->is_pipe) 695 lseek(fd, output_data_offset, SEEK_SET); 696 697 ret = perf_session__process_events(session); 698 if (ret) 699 return ret; 700 701 if (!data_out->is_pipe) { 702 if (inject->build_ids) 703 perf_header__set_feat(&session->header, 704 HEADER_BUILD_ID); 705 /* 706 * Keep all buildids when there is unprocessed AUX data because 707 * it is not known which ones the AUX trace hits. 708 */ 709 if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) && 710 inject->have_auxtrace && !inject->itrace_synth_opts.set) 711 dsos__hit_all(session); 712 /* 713 * The AUX areas have been removed and replaced with 714 * synthesized hardware events, so clear the feature flag and 715 * remove the evsel. 716 */ 717 if (inject->itrace_synth_opts.set) { 718 struct perf_evsel *evsel; 719 720 perf_header__clear_feat(&session->header, 721 HEADER_AUXTRACE); 722 if (inject->itrace_synth_opts.last_branch) 723 perf_header__set_feat(&session->header, 724 HEADER_BRANCH_STACK); 725 evsel = perf_evlist__id2evsel_strict(session->evlist, 726 inject->aux_id); 727 if (evsel) { 728 pr_debug("Deleting %s\n", 729 perf_evsel__name(evsel)); 730 perf_evlist__remove(session->evlist, evsel); 731 perf_evsel__delete(evsel); 732 } 733 if (inject->strip) 734 strip_fini(inject); 735 } 736 session->header.data_offset = output_data_offset; 737 session->header.data_size = inject->bytes_written; 738 perf_session__write_header(session, session->evlist, fd, true); 739 } 740 741 return ret; 742 } 743 744 int cmd_inject(int argc, const char **argv) 745 { 746 struct perf_inject inject = { 747 .tool = { 748 .sample = perf_event__repipe_sample, 749 .mmap = perf_event__repipe, 750 .mmap2 = perf_event__repipe, 751 .comm = perf_event__repipe, 752 .fork = perf_event__repipe, 753 .exit = perf_event__repipe, 754 .lost = perf_event__repipe, 755 .lost_samples = perf_event__repipe, 756 .aux = perf_event__repipe, 757 .itrace_start = perf_event__repipe, 758 .context_switch = perf_event__repipe, 759 .read = perf_event__repipe_sample, 760 .throttle = perf_event__repipe, 761 .unthrottle = perf_event__repipe, 762 .attr = perf_event__repipe_attr, 763 .tracing_data = perf_event__repipe_op2_synth, 764 .auxtrace_info = perf_event__repipe_op2_synth, 765 .auxtrace = perf_event__repipe_auxtrace, 766 .auxtrace_error = perf_event__repipe_op2_synth, 767 .time_conv = perf_event__repipe_op2_synth, 768 .finished_round = perf_event__repipe_oe_synth, 769 .build_id = perf_event__repipe_op2_synth, 770 .id_index = perf_event__repipe_op2_synth, 771 .feature = perf_event__repipe_op2_synth, 772 }, 773 .input_name = "-", 774 .samples = LIST_HEAD_INIT(inject.samples), 775 .output = { 776 .file = { 777 .path = "-", 778 }, 779 .mode = PERF_DATA_MODE_WRITE, 780 }, 781 }; 782 struct perf_data data = { 783 .mode = PERF_DATA_MODE_READ, 784 }; 785 int ret; 786 787 struct option options[] = { 788 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 789 "Inject build-ids into the output stream"), 790 OPT_STRING('i', "input", &inject.input_name, "file", 791 "input file name"), 792 OPT_STRING('o', "output", &inject.output.file.path, "file", 793 "output file name"), 794 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 795 "Merge sched-stat and sched-switch for getting events " 796 "where and how long tasks slept"), 797 #ifdef HAVE_JITDUMP 798 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"), 799 #endif 800 OPT_INCR('v', "verbose", &verbose, 801 "be more verbose (show build ids, etc)"), 802 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 803 "kallsyms pathname"), 804 OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), 805 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, 806 NULL, "opts", "Instruction Tracing options", 807 itrace_parse_synth_opts), 808 OPT_BOOLEAN(0, "strip", &inject.strip, 809 "strip non-synthesized events (use with --itrace)"), 810 OPT_END() 811 }; 812 const char * const inject_usage[] = { 813 "perf inject [<options>]", 814 NULL 815 }; 816 #ifndef HAVE_JITDUMP 817 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true); 818 #endif 819 argc = parse_options(argc, argv, options, inject_usage, 0); 820 821 /* 822 * Any (unrecognized) arguments left? 823 */ 824 if (argc) 825 usage_with_options(inject_usage, options); 826 827 if (inject.strip && !inject.itrace_synth_opts.set) { 828 pr_err("--strip option requires --itrace option\n"); 829 return -1; 830 } 831 832 if (perf_data__open(&inject.output)) { 833 perror("failed to create output file"); 834 return -1; 835 } 836 837 inject.tool.ordered_events = inject.sched_stat; 838 839 data.file.path = inject.input_name; 840 inject.session = perf_session__new(&data, true, &inject.tool); 841 if (inject.session == NULL) 842 return -1; 843 844 if (inject.build_ids) { 845 /* 846 * to make sure the mmap records are ordered correctly 847 * and so that the correct especially due to jitted code 848 * mmaps. We cannot generate the buildid hit list and 849 * inject the jit mmaps at the same time for now. 850 */ 851 inject.tool.ordered_events = true; 852 inject.tool.ordering_requires_timestamps = true; 853 } 854 #ifdef HAVE_JITDUMP 855 if (inject.jit_mode) { 856 inject.tool.mmap2 = perf_event__jit_repipe_mmap2; 857 inject.tool.mmap = perf_event__jit_repipe_mmap; 858 inject.tool.ordered_events = true; 859 inject.tool.ordering_requires_timestamps = true; 860 /* 861 * JIT MMAP injection injects all MMAP events in one go, so it 862 * does not obey finished_round semantics. 863 */ 864 inject.tool.finished_round = perf_event__drop_oe; 865 } 866 #endif 867 ret = symbol__init(&inject.session->header.env); 868 if (ret < 0) 869 goto out_delete; 870 871 ret = __cmd_inject(&inject); 872 873 out_delete: 874 perf_session__delete(inject.session); 875 return ret; 876 } 877