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