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