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