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 #include "util/thread.h" 22 23 #include <subcmd/parse-options.h> 24 25 #include <linux/list.h> 26 #include <errno.h> 27 #include <signal.h> 28 29 struct perf_inject { 30 struct perf_tool tool; 31 struct perf_session *session; 32 bool build_ids; 33 bool sched_stat; 34 bool have_auxtrace; 35 bool strip; 36 bool jit_mode; 37 const char *input_name; 38 struct perf_data_file output; 39 u64 bytes_written; 40 u64 aux_id; 41 struct list_head samples; 42 struct itrace_synth_opts itrace_synth_opts; 43 }; 44 45 struct event_entry { 46 struct list_head node; 47 u32 tid; 48 union perf_event event[0]; 49 }; 50 51 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz) 52 { 53 ssize_t size; 54 55 size = perf_data_file__write(&inject->output, buf, sz); 56 if (size < 0) 57 return -errno; 58 59 inject->bytes_written += size; 60 return 0; 61 } 62 63 static int perf_event__repipe_synth(struct perf_tool *tool, 64 union perf_event *event) 65 { 66 struct perf_inject *inject = container_of(tool, struct perf_inject, 67 tool); 68 69 return output_bytes(inject, event, event->header.size); 70 } 71 72 static int perf_event__repipe_oe_synth(struct perf_tool *tool, 73 union perf_event *event, 74 struct ordered_events *oe __maybe_unused) 75 { 76 return perf_event__repipe_synth(tool, event); 77 } 78 79 #ifdef HAVE_JITDUMP 80 static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused, 81 union perf_event *event __maybe_unused, 82 struct ordered_events *oe __maybe_unused) 83 { 84 return 0; 85 } 86 #endif 87 88 static int perf_event__repipe_op2_synth(struct perf_tool *tool, 89 union perf_event *event, 90 struct perf_session *session 91 __maybe_unused) 92 { 93 return perf_event__repipe_synth(tool, event); 94 } 95 96 static int perf_event__repipe_attr(struct perf_tool *tool, 97 union perf_event *event, 98 struct perf_evlist **pevlist) 99 { 100 struct perf_inject *inject = container_of(tool, struct perf_inject, 101 tool); 102 int ret; 103 104 ret = perf_event__process_attr(tool, event, pevlist); 105 if (ret) 106 return ret; 107 108 if (!inject->output.is_pipe) 109 return 0; 110 111 return perf_event__repipe_synth(tool, event); 112 } 113 114 #ifdef HAVE_AUXTRACE_SUPPORT 115 116 static int copy_bytes(struct perf_inject *inject, int fd, off_t size) 117 { 118 char buf[4096]; 119 ssize_t ssz; 120 int ret; 121 122 while (size > 0) { 123 ssz = read(fd, buf, min(size, (off_t)sizeof(buf))); 124 if (ssz < 0) 125 return -errno; 126 ret = output_bytes(inject, buf, ssz); 127 if (ret) 128 return ret; 129 size -= ssz; 130 } 131 132 return 0; 133 } 134 135 static s64 perf_event__repipe_auxtrace(struct perf_tool *tool, 136 union perf_event *event, 137 struct perf_session *session) 138 { 139 struct perf_inject *inject = container_of(tool, struct perf_inject, 140 tool); 141 int ret; 142 143 inject->have_auxtrace = true; 144 145 if (!inject->output.is_pipe) { 146 off_t offset; 147 148 offset = lseek(inject->output.fd, 0, SEEK_CUR); 149 if (offset == -1) 150 return -errno; 151 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index, 152 event, offset); 153 if (ret < 0) 154 return ret; 155 } 156 157 if (perf_data_file__is_pipe(session->file) || !session->one_mmap) { 158 ret = output_bytes(inject, event, event->header.size); 159 if (ret < 0) 160 return ret; 161 ret = copy_bytes(inject, perf_data_file__fd(session->file), 162 event->auxtrace.size); 163 } else { 164 ret = output_bytes(inject, event, 165 event->header.size + event->auxtrace.size); 166 } 167 if (ret < 0) 168 return ret; 169 170 return event->auxtrace.size; 171 } 172 173 #else 174 175 static s64 176 perf_event__repipe_auxtrace(struct perf_tool *tool __maybe_unused, 177 union perf_event *event __maybe_unused, 178 struct perf_session *session __maybe_unused) 179 { 180 pr_err("AUX area tracing not supported\n"); 181 return -EINVAL; 182 } 183 184 #endif 185 186 static int perf_event__repipe(struct perf_tool *tool, 187 union perf_event *event, 188 struct perf_sample *sample __maybe_unused, 189 struct machine *machine __maybe_unused) 190 { 191 return perf_event__repipe_synth(tool, event); 192 } 193 194 static int perf_event__drop(struct perf_tool *tool __maybe_unused, 195 union perf_event *event __maybe_unused, 196 struct perf_sample *sample __maybe_unused, 197 struct machine *machine __maybe_unused) 198 { 199 return 0; 200 } 201 202 static int perf_event__drop_aux(struct perf_tool *tool, 203 union perf_event *event __maybe_unused, 204 struct perf_sample *sample, 205 struct machine *machine __maybe_unused) 206 { 207 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 208 209 if (!inject->aux_id) 210 inject->aux_id = sample->id; 211 212 return 0; 213 } 214 215 typedef int (*inject_handler)(struct perf_tool *tool, 216 union perf_event *event, 217 struct perf_sample *sample, 218 struct perf_evsel *evsel, 219 struct machine *machine); 220 221 static int perf_event__repipe_sample(struct perf_tool *tool, 222 union perf_event *event, 223 struct perf_sample *sample, 224 struct perf_evsel *evsel, 225 struct machine *machine) 226 { 227 if (evsel->handler) { 228 inject_handler f = evsel->handler; 229 return f(tool, event, sample, evsel, machine); 230 } 231 232 build_id__mark_dso_hit(tool, event, sample, evsel, machine); 233 234 return perf_event__repipe_synth(tool, event); 235 } 236 237 static int perf_event__repipe_mmap(struct perf_tool *tool, 238 union perf_event *event, 239 struct perf_sample *sample, 240 struct machine *machine) 241 { 242 int err; 243 244 err = perf_event__process_mmap(tool, event, sample, machine); 245 perf_event__repipe(tool, event, sample, machine); 246 247 return err; 248 } 249 250 #ifdef HAVE_JITDUMP 251 static int perf_event__jit_repipe_mmap(struct perf_tool *tool, 252 union perf_event *event, 253 struct perf_sample *sample, 254 struct machine *machine) 255 { 256 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 257 u64 n = 0; 258 int ret; 259 260 /* 261 * if jit marker, then inject jit mmaps and generate ELF images 262 */ 263 ret = jit_process(inject->session, &inject->output, machine, 264 event->mmap.filename, sample->pid, &n); 265 if (ret < 0) 266 return ret; 267 if (ret) { 268 inject->bytes_written += n; 269 return 0; 270 } 271 return perf_event__repipe_mmap(tool, event, sample, machine); 272 } 273 #endif 274 275 static int perf_event__repipe_mmap2(struct perf_tool *tool, 276 union perf_event *event, 277 struct perf_sample *sample, 278 struct machine *machine) 279 { 280 int err; 281 282 err = perf_event__process_mmap2(tool, event, sample, machine); 283 perf_event__repipe(tool, event, sample, machine); 284 285 return err; 286 } 287 288 #ifdef HAVE_JITDUMP 289 static int perf_event__jit_repipe_mmap2(struct perf_tool *tool, 290 union perf_event *event, 291 struct perf_sample *sample, 292 struct machine *machine) 293 { 294 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 295 u64 n = 0; 296 int ret; 297 298 /* 299 * if jit marker, then inject jit mmaps and generate ELF images 300 */ 301 ret = jit_process(inject->session, &inject->output, machine, 302 event->mmap2.filename, sample->pid, &n); 303 if (ret < 0) 304 return ret; 305 if (ret) { 306 inject->bytes_written += n; 307 return 0; 308 } 309 return perf_event__repipe_mmap2(tool, event, sample, machine); 310 } 311 #endif 312 313 static int perf_event__repipe_fork(struct perf_tool *tool, 314 union perf_event *event, 315 struct perf_sample *sample, 316 struct machine *machine) 317 { 318 int err; 319 320 err = perf_event__process_fork(tool, event, sample, machine); 321 perf_event__repipe(tool, event, sample, machine); 322 323 return err; 324 } 325 326 static int perf_event__repipe_comm(struct perf_tool *tool, 327 union perf_event *event, 328 struct perf_sample *sample, 329 struct machine *machine) 330 { 331 int err; 332 333 err = perf_event__process_comm(tool, event, sample, machine); 334 perf_event__repipe(tool, event, sample, machine); 335 336 return err; 337 } 338 339 static int perf_event__repipe_namespaces(struct perf_tool *tool, 340 union perf_event *event, 341 struct perf_sample *sample, 342 struct machine *machine) 343 { 344 int err = perf_event__process_namespaces(tool, event, sample, machine); 345 346 perf_event__repipe(tool, event, sample, machine); 347 348 return err; 349 } 350 351 static int perf_event__repipe_exit(struct perf_tool *tool, 352 union perf_event *event, 353 struct perf_sample *sample, 354 struct machine *machine) 355 { 356 int err; 357 358 err = perf_event__process_exit(tool, event, sample, machine); 359 perf_event__repipe(tool, event, sample, machine); 360 361 return err; 362 } 363 364 static int perf_event__repipe_tracing_data(struct perf_tool *tool, 365 union perf_event *event, 366 struct perf_session *session) 367 { 368 int err; 369 370 perf_event__repipe_synth(tool, event); 371 err = perf_event__process_tracing_data(tool, event, session); 372 373 return err; 374 } 375 376 static int perf_event__repipe_id_index(struct perf_tool *tool, 377 union perf_event *event, 378 struct perf_session *session) 379 { 380 int err; 381 382 perf_event__repipe_synth(tool, event); 383 err = perf_event__process_id_index(tool, event, session); 384 385 return err; 386 } 387 388 static int dso__read_build_id(struct dso *dso) 389 { 390 if (dso->has_build_id) 391 return 0; 392 393 if (filename__read_build_id(dso->long_name, dso->build_id, 394 sizeof(dso->build_id)) > 0) { 395 dso->has_build_id = true; 396 return 0; 397 } 398 399 return -1; 400 } 401 402 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, 403 struct machine *machine) 404 { 405 u16 misc = PERF_RECORD_MISC_USER; 406 int err; 407 408 if (dso__read_build_id(dso) < 0) { 409 pr_debug("no build_id found for %s\n", dso->long_name); 410 return -1; 411 } 412 413 if (dso->kernel) 414 misc = PERF_RECORD_MISC_KERNEL; 415 416 err = perf_event__synthesize_build_id(tool, dso, misc, perf_event__repipe, 417 machine); 418 if (err) { 419 pr_err("Can't synthesize build_id event for %s\n", dso->long_name); 420 return -1; 421 } 422 423 return 0; 424 } 425 426 static int perf_event__inject_buildid(struct perf_tool *tool, 427 union perf_event *event, 428 struct perf_sample *sample, 429 struct perf_evsel *evsel __maybe_unused, 430 struct machine *machine) 431 { 432 struct addr_location al; 433 struct thread *thread; 434 435 thread = machine__findnew_thread(machine, sample->pid, sample->tid); 436 if (thread == NULL) { 437 pr_err("problem processing %d event, skipping it.\n", 438 event->header.type); 439 goto repipe; 440 } 441 442 thread__find_addr_map(thread, sample->cpumode, MAP__FUNCTION, sample->ip, &al); 443 444 if (al.map != NULL) { 445 if (!al.map->dso->hit) { 446 al.map->dso->hit = 1; 447 if (map__load(al.map) >= 0) { 448 dso__inject_build_id(al.map->dso, tool, machine); 449 /* 450 * If this fails, too bad, let the other side 451 * account this as unresolved. 452 */ 453 } else { 454 #ifdef HAVE_LIBELF_SUPPORT 455 pr_warning("no symbols found in %s, maybe " 456 "install a debug package?\n", 457 al.map->dso->long_name); 458 #endif 459 } 460 } 461 } 462 463 thread__put(thread); 464 repipe: 465 perf_event__repipe(tool, event, sample, machine); 466 return 0; 467 } 468 469 static int perf_inject__sched_process_exit(struct perf_tool *tool, 470 union perf_event *event __maybe_unused, 471 struct perf_sample *sample, 472 struct perf_evsel *evsel __maybe_unused, 473 struct machine *machine __maybe_unused) 474 { 475 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 476 struct event_entry *ent; 477 478 list_for_each_entry(ent, &inject->samples, node) { 479 if (sample->tid == ent->tid) { 480 list_del_init(&ent->node); 481 free(ent); 482 break; 483 } 484 } 485 486 return 0; 487 } 488 489 static int perf_inject__sched_switch(struct perf_tool *tool, 490 union perf_event *event, 491 struct perf_sample *sample, 492 struct perf_evsel *evsel, 493 struct machine *machine) 494 { 495 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 496 struct event_entry *ent; 497 498 perf_inject__sched_process_exit(tool, event, sample, evsel, machine); 499 500 ent = malloc(event->header.size + sizeof(struct event_entry)); 501 if (ent == NULL) { 502 color_fprintf(stderr, PERF_COLOR_RED, 503 "Not enough memory to process sched switch event!"); 504 return -1; 505 } 506 507 ent->tid = sample->tid; 508 memcpy(&ent->event, event, event->header.size); 509 list_add(&ent->node, &inject->samples); 510 return 0; 511 } 512 513 static int perf_inject__sched_stat(struct perf_tool *tool, 514 union perf_event *event __maybe_unused, 515 struct perf_sample *sample, 516 struct perf_evsel *evsel, 517 struct machine *machine) 518 { 519 struct event_entry *ent; 520 union perf_event *event_sw; 521 struct perf_sample sample_sw; 522 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 523 u32 pid = perf_evsel__intval(evsel, sample, "pid"); 524 525 list_for_each_entry(ent, &inject->samples, node) { 526 if (pid == ent->tid) 527 goto found; 528 } 529 530 return 0; 531 found: 532 event_sw = &ent->event[0]; 533 perf_evsel__parse_sample(evsel, event_sw, &sample_sw); 534 535 sample_sw.period = sample->period; 536 sample_sw.time = sample->time; 537 perf_event__synthesize_sample(event_sw, evsel->attr.sample_type, 538 evsel->attr.read_format, &sample_sw, 539 false); 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_file *file_out = &inject->output; 641 int fd = perf_data_file__fd(file_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 (!file_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 (!file_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 }, 774 .input_name = "-", 775 .samples = LIST_HEAD_INIT(inject.samples), 776 .output = { 777 .path = "-", 778 .mode = PERF_DATA_MODE_WRITE, 779 }, 780 }; 781 struct perf_data_file file = { 782 .mode = PERF_DATA_MODE_READ, 783 }; 784 int ret; 785 786 struct option options[] = { 787 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 788 "Inject build-ids into the output stream"), 789 OPT_STRING('i', "input", &inject.input_name, "file", 790 "input file name"), 791 OPT_STRING('o', "output", &inject.output.path, "file", 792 "output file name"), 793 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 794 "Merge sched-stat and sched-switch for getting events " 795 "where and how long tasks slept"), 796 #ifdef HAVE_JITDUMP 797 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"), 798 #endif 799 OPT_INCR('v', "verbose", &verbose, 800 "be more verbose (show build ids, etc)"), 801 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 802 "kallsyms pathname"), 803 OPT_BOOLEAN('f', "force", &file.force, "don't complain, do it"), 804 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, 805 NULL, "opts", "Instruction Tracing options", 806 itrace_parse_synth_opts), 807 OPT_BOOLEAN(0, "strip", &inject.strip, 808 "strip non-synthesized events (use with --itrace)"), 809 OPT_END() 810 }; 811 const char * const inject_usage[] = { 812 "perf inject [<options>]", 813 NULL 814 }; 815 #ifndef HAVE_JITDUMP 816 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true); 817 #endif 818 argc = parse_options(argc, argv, options, inject_usage, 0); 819 820 /* 821 * Any (unrecognized) arguments left? 822 */ 823 if (argc) 824 usage_with_options(inject_usage, options); 825 826 if (inject.strip && !inject.itrace_synth_opts.set) { 827 pr_err("--strip option requires --itrace option\n"); 828 return -1; 829 } 830 831 if (perf_data_file__open(&inject.output)) { 832 perror("failed to create output file"); 833 return -1; 834 } 835 836 inject.tool.ordered_events = inject.sched_stat; 837 838 file.path = inject.input_name; 839 inject.session = perf_session__new(&file, true, &inject.tool); 840 if (inject.session == NULL) 841 return -1; 842 843 if (inject.build_ids) { 844 /* 845 * to make sure the mmap records are ordered correctly 846 * and so that the correct especially due to jitted code 847 * mmaps. We cannot generate the buildid hit list and 848 * inject the jit mmaps at the same time for now. 849 */ 850 inject.tool.ordered_events = true; 851 inject.tool.ordering_requires_timestamps = true; 852 } 853 #ifdef HAVE_JITDUMP 854 if (inject.jit_mode) { 855 inject.tool.mmap2 = perf_event__jit_repipe_mmap2; 856 inject.tool.mmap = perf_event__jit_repipe_mmap; 857 inject.tool.ordered_events = true; 858 inject.tool.ordering_requires_timestamps = true; 859 /* 860 * JIT MMAP injection injects all MMAP events in one go, so it 861 * does not obey finished_round semantics. 862 */ 863 inject.tool.finished_round = perf_event__drop_oe; 864 } 865 #endif 866 ret = symbol__init(&inject.session->header.env); 867 if (ret < 0) 868 goto out_delete; 869 870 ret = __cmd_inject(&inject); 871 872 out_delete: 873 perf_session__delete(inject.session); 874 return ret; 875 } 876