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 "util/color.h" 12 #include "util/dso.h" 13 #include "util/vdso.h" 14 #include "util/evlist.h" 15 #include "util/evsel.h" 16 #include "util/map.h" 17 #include "util/session.h" 18 #include "util/tool.h" 19 #include "util/debug.h" 20 #include "util/build-id.h" 21 #include "util/data.h" 22 #include "util/auxtrace.h" 23 #include "util/jit.h" 24 #include "util/symbol.h" 25 #include "util/synthetic-events.h" 26 #include "util/thread.h" 27 #include "util/namespaces.h" 28 29 #include <linux/err.h> 30 #include <subcmd/parse-options.h> 31 #include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */ 32 33 #include <linux/list.h> 34 #include <linux/string.h> 35 #include <errno.h> 36 #include <signal.h> 37 38 struct perf_inject { 39 struct perf_tool tool; 40 struct perf_session *session; 41 bool build_ids; 42 bool build_id_all; 43 bool sched_stat; 44 bool have_auxtrace; 45 bool strip; 46 bool jit_mode; 47 bool in_place_update; 48 bool in_place_update_dry_run; 49 const char *input_name; 50 struct perf_data output; 51 u64 bytes_written; 52 u64 aux_id; 53 struct list_head samples; 54 struct itrace_synth_opts itrace_synth_opts; 55 char event_copy[PERF_SAMPLE_MAX_SIZE]; 56 }; 57 58 struct event_entry { 59 struct list_head node; 60 u32 tid; 61 union perf_event event[]; 62 }; 63 64 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, 65 struct machine *machine, u8 cpumode, u32 flags); 66 67 static int output_bytes(struct perf_inject *inject, void *buf, size_t sz) 68 { 69 ssize_t size; 70 71 size = perf_data__write(&inject->output, buf, sz); 72 if (size < 0) 73 return -errno; 74 75 inject->bytes_written += size; 76 return 0; 77 } 78 79 static int perf_event__repipe_synth(struct perf_tool *tool, 80 union perf_event *event) 81 { 82 struct perf_inject *inject = container_of(tool, struct perf_inject, 83 tool); 84 85 return output_bytes(inject, event, event->header.size); 86 } 87 88 static int perf_event__repipe_oe_synth(struct perf_tool *tool, 89 union perf_event *event, 90 struct ordered_events *oe __maybe_unused) 91 { 92 return perf_event__repipe_synth(tool, event); 93 } 94 95 #ifdef HAVE_JITDUMP 96 static int perf_event__drop_oe(struct perf_tool *tool __maybe_unused, 97 union perf_event *event __maybe_unused, 98 struct ordered_events *oe __maybe_unused) 99 { 100 return 0; 101 } 102 #endif 103 104 static int perf_event__repipe_op2_synth(struct perf_session *session, 105 union perf_event *event) 106 { 107 return perf_event__repipe_synth(session->tool, event); 108 } 109 110 static int perf_event__repipe_op4_synth(struct perf_session *session, 111 union perf_event *event, 112 u64 data __maybe_unused) 113 { 114 return perf_event__repipe_synth(session->tool, event); 115 } 116 117 static int perf_event__repipe_attr(struct perf_tool *tool, 118 union perf_event *event, 119 struct evlist **pevlist) 120 { 121 struct perf_inject *inject = container_of(tool, struct perf_inject, 122 tool); 123 int ret; 124 125 ret = perf_event__process_attr(tool, event, pevlist); 126 if (ret) 127 return ret; 128 129 if (!inject->output.is_pipe) 130 return 0; 131 132 return perf_event__repipe_synth(tool, event); 133 } 134 135 static int perf_event__repipe_event_update(struct perf_tool *tool, 136 union perf_event *event, 137 struct evlist **pevlist __maybe_unused) 138 { 139 return perf_event__repipe_synth(tool, event); 140 } 141 142 #ifdef HAVE_AUXTRACE_SUPPORT 143 144 static int copy_bytes(struct perf_inject *inject, int fd, off_t size) 145 { 146 char buf[4096]; 147 ssize_t ssz; 148 int ret; 149 150 while (size > 0) { 151 ssz = read(fd, buf, min(size, (off_t)sizeof(buf))); 152 if (ssz < 0) 153 return -errno; 154 ret = output_bytes(inject, buf, ssz); 155 if (ret) 156 return ret; 157 size -= ssz; 158 } 159 160 return 0; 161 } 162 163 static s64 perf_event__repipe_auxtrace(struct perf_session *session, 164 union perf_event *event) 165 { 166 struct perf_tool *tool = session->tool; 167 struct perf_inject *inject = container_of(tool, struct perf_inject, 168 tool); 169 int ret; 170 171 inject->have_auxtrace = true; 172 173 if (!inject->output.is_pipe) { 174 off_t offset; 175 176 offset = lseek(inject->output.file.fd, 0, SEEK_CUR); 177 if (offset == -1) 178 return -errno; 179 ret = auxtrace_index__auxtrace_event(&session->auxtrace_index, 180 event, offset); 181 if (ret < 0) 182 return ret; 183 } 184 185 if (perf_data__is_pipe(session->data) || !session->one_mmap) { 186 ret = output_bytes(inject, event, event->header.size); 187 if (ret < 0) 188 return ret; 189 ret = copy_bytes(inject, perf_data__fd(session->data), 190 event->auxtrace.size); 191 } else { 192 ret = output_bytes(inject, event, 193 event->header.size + event->auxtrace.size); 194 } 195 if (ret < 0) 196 return ret; 197 198 return event->auxtrace.size; 199 } 200 201 #else 202 203 static s64 204 perf_event__repipe_auxtrace(struct perf_session *session __maybe_unused, 205 union perf_event *event __maybe_unused) 206 { 207 pr_err("AUX area tracing not supported\n"); 208 return -EINVAL; 209 } 210 211 #endif 212 213 static int perf_event__repipe(struct perf_tool *tool, 214 union perf_event *event, 215 struct perf_sample *sample __maybe_unused, 216 struct machine *machine __maybe_unused) 217 { 218 return perf_event__repipe_synth(tool, event); 219 } 220 221 static int perf_event__drop(struct perf_tool *tool __maybe_unused, 222 union perf_event *event __maybe_unused, 223 struct perf_sample *sample __maybe_unused, 224 struct machine *machine __maybe_unused) 225 { 226 return 0; 227 } 228 229 static int perf_event__drop_aux(struct perf_tool *tool, 230 union perf_event *event __maybe_unused, 231 struct perf_sample *sample, 232 struct machine *machine __maybe_unused) 233 { 234 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 235 236 if (!inject->aux_id) 237 inject->aux_id = sample->id; 238 239 return 0; 240 } 241 242 static union perf_event * 243 perf_inject__cut_auxtrace_sample(struct perf_inject *inject, 244 union perf_event *event, 245 struct perf_sample *sample) 246 { 247 size_t sz1 = sample->aux_sample.data - (void *)event; 248 size_t sz2 = event->header.size - sample->aux_sample.size - sz1; 249 union perf_event *ev = (union perf_event *)inject->event_copy; 250 251 if (sz1 > event->header.size || sz2 > event->header.size || 252 sz1 + sz2 > event->header.size || 253 sz1 < sizeof(struct perf_event_header) + sizeof(u64)) 254 return event; 255 256 memcpy(ev, event, sz1); 257 memcpy((void *)ev + sz1, (void *)event + event->header.size - sz2, sz2); 258 ev->header.size = sz1 + sz2; 259 ((u64 *)((void *)ev + sz1))[-1] = 0; 260 261 return ev; 262 } 263 264 typedef int (*inject_handler)(struct perf_tool *tool, 265 union perf_event *event, 266 struct perf_sample *sample, 267 struct evsel *evsel, 268 struct machine *machine); 269 270 static int perf_event__repipe_sample(struct perf_tool *tool, 271 union perf_event *event, 272 struct perf_sample *sample, 273 struct evsel *evsel, 274 struct machine *machine) 275 { 276 struct perf_inject *inject = container_of(tool, struct perf_inject, 277 tool); 278 279 if (evsel && evsel->handler) { 280 inject_handler f = evsel->handler; 281 return f(tool, event, sample, evsel, machine); 282 } 283 284 build_id__mark_dso_hit(tool, event, sample, evsel, machine); 285 286 if (inject->itrace_synth_opts.set && sample->aux_sample.size) 287 event = perf_inject__cut_auxtrace_sample(inject, event, sample); 288 289 return perf_event__repipe_synth(tool, event); 290 } 291 292 static int perf_event__repipe_mmap(struct perf_tool *tool, 293 union perf_event *event, 294 struct perf_sample *sample, 295 struct machine *machine) 296 { 297 int err; 298 299 err = perf_event__process_mmap(tool, event, sample, machine); 300 perf_event__repipe(tool, event, sample, machine); 301 302 return err; 303 } 304 305 #ifdef HAVE_JITDUMP 306 static int perf_event__jit_repipe_mmap(struct perf_tool *tool, 307 union perf_event *event, 308 struct perf_sample *sample, 309 struct machine *machine) 310 { 311 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 312 u64 n = 0; 313 int ret; 314 315 /* 316 * if jit marker, then inject jit mmaps and generate ELF images 317 */ 318 ret = jit_process(inject->session, &inject->output, machine, 319 event->mmap.filename, event->mmap.pid, event->mmap.tid, &n); 320 if (ret < 0) 321 return ret; 322 if (ret) { 323 inject->bytes_written += n; 324 return 0; 325 } 326 return perf_event__repipe_mmap(tool, event, sample, machine); 327 } 328 #endif 329 330 static struct dso *findnew_dso(int pid, int tid, const char *filename, 331 struct dso_id *id, struct machine *machine) 332 { 333 struct thread *thread; 334 struct nsinfo *nsi = NULL; 335 struct nsinfo *nnsi; 336 struct dso *dso; 337 bool vdso; 338 339 thread = machine__findnew_thread(machine, pid, tid); 340 if (thread == NULL) { 341 pr_err("cannot find or create a task %d/%d.\n", tid, pid); 342 return NULL; 343 } 344 345 vdso = is_vdso_map(filename); 346 nsi = nsinfo__get(thread->nsinfo); 347 348 if (vdso) { 349 /* The vdso maps are always on the host and not the 350 * container. Ensure that we don't use setns to look 351 * them up. 352 */ 353 nnsi = nsinfo__copy(nsi); 354 if (nnsi) { 355 nsinfo__put(nsi); 356 nnsi->need_setns = false; 357 nsi = nnsi; 358 } 359 dso = machine__findnew_vdso(machine, thread); 360 } else { 361 dso = machine__findnew_dso_id(machine, filename, id); 362 } 363 364 if (dso) 365 dso->nsinfo = nsi; 366 else 367 nsinfo__put(nsi); 368 369 thread__put(thread); 370 return dso; 371 } 372 373 static int perf_event__repipe_buildid_mmap(struct perf_tool *tool, 374 union perf_event *event, 375 struct perf_sample *sample, 376 struct machine *machine) 377 { 378 struct dso *dso; 379 380 dso = findnew_dso(event->mmap.pid, event->mmap.tid, 381 event->mmap.filename, NULL, machine); 382 383 if (dso && !dso->hit) { 384 dso->hit = 1; 385 dso__inject_build_id(dso, tool, machine, sample->cpumode, 0); 386 } 387 dso__put(dso); 388 389 return perf_event__repipe(tool, event, sample, machine); 390 } 391 392 static int perf_event__repipe_mmap2(struct perf_tool *tool, 393 union perf_event *event, 394 struct perf_sample *sample, 395 struct machine *machine) 396 { 397 int err; 398 399 err = perf_event__process_mmap2(tool, event, sample, machine); 400 perf_event__repipe(tool, event, sample, machine); 401 402 if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) { 403 struct dso *dso; 404 405 dso = findnew_dso(event->mmap2.pid, event->mmap2.tid, 406 event->mmap2.filename, NULL, machine); 407 if (dso) { 408 /* mark it not to inject build-id */ 409 dso->hit = 1; 410 } 411 dso__put(dso); 412 } 413 414 return err; 415 } 416 417 #ifdef HAVE_JITDUMP 418 static int perf_event__jit_repipe_mmap2(struct perf_tool *tool, 419 union perf_event *event, 420 struct perf_sample *sample, 421 struct machine *machine) 422 { 423 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 424 u64 n = 0; 425 int ret; 426 427 /* 428 * if jit marker, then inject jit mmaps and generate ELF images 429 */ 430 ret = jit_process(inject->session, &inject->output, machine, 431 event->mmap2.filename, event->mmap2.pid, event->mmap2.tid, &n); 432 if (ret < 0) 433 return ret; 434 if (ret) { 435 inject->bytes_written += n; 436 return 0; 437 } 438 return perf_event__repipe_mmap2(tool, event, sample, machine); 439 } 440 #endif 441 442 static int perf_event__repipe_buildid_mmap2(struct perf_tool *tool, 443 union perf_event *event, 444 struct perf_sample *sample, 445 struct machine *machine) 446 { 447 struct dso_id dso_id = { 448 .maj = event->mmap2.maj, 449 .min = event->mmap2.min, 450 .ino = event->mmap2.ino, 451 .ino_generation = event->mmap2.ino_generation, 452 }; 453 struct dso *dso; 454 455 if (event->header.misc & PERF_RECORD_MISC_MMAP_BUILD_ID) { 456 /* cannot use dso_id since it'd have invalid info */ 457 dso = findnew_dso(event->mmap2.pid, event->mmap2.tid, 458 event->mmap2.filename, NULL, machine); 459 if (dso) { 460 /* mark it not to inject build-id */ 461 dso->hit = 1; 462 } 463 dso__put(dso); 464 return 0; 465 } 466 467 dso = findnew_dso(event->mmap2.pid, event->mmap2.tid, 468 event->mmap2.filename, &dso_id, machine); 469 470 if (dso && !dso->hit) { 471 dso->hit = 1; 472 dso__inject_build_id(dso, tool, machine, sample->cpumode, 473 event->mmap2.flags); 474 } 475 dso__put(dso); 476 477 perf_event__repipe(tool, event, sample, machine); 478 479 return 0; 480 } 481 482 static int perf_event__repipe_fork(struct perf_tool *tool, 483 union perf_event *event, 484 struct perf_sample *sample, 485 struct machine *machine) 486 { 487 int err; 488 489 err = perf_event__process_fork(tool, event, sample, machine); 490 perf_event__repipe(tool, event, sample, machine); 491 492 return err; 493 } 494 495 static int perf_event__repipe_comm(struct perf_tool *tool, 496 union perf_event *event, 497 struct perf_sample *sample, 498 struct machine *machine) 499 { 500 int err; 501 502 err = perf_event__process_comm(tool, event, sample, machine); 503 perf_event__repipe(tool, event, sample, machine); 504 505 return err; 506 } 507 508 static int perf_event__repipe_namespaces(struct perf_tool *tool, 509 union perf_event *event, 510 struct perf_sample *sample, 511 struct machine *machine) 512 { 513 int err = perf_event__process_namespaces(tool, event, sample, machine); 514 515 perf_event__repipe(tool, event, sample, machine); 516 517 return err; 518 } 519 520 static int perf_event__repipe_exit(struct perf_tool *tool, 521 union perf_event *event, 522 struct perf_sample *sample, 523 struct machine *machine) 524 { 525 int err; 526 527 err = perf_event__process_exit(tool, event, sample, machine); 528 perf_event__repipe(tool, event, sample, machine); 529 530 return err; 531 } 532 533 static int perf_event__repipe_tracing_data(struct perf_session *session, 534 union perf_event *event) 535 { 536 int err; 537 538 perf_event__repipe_synth(session->tool, event); 539 err = perf_event__process_tracing_data(session, event); 540 541 return err; 542 } 543 544 static int dso__read_build_id(struct dso *dso) 545 { 546 struct nscookie nsc; 547 548 if (dso->has_build_id) 549 return 0; 550 551 nsinfo__mountns_enter(dso->nsinfo, &nsc); 552 if (filename__read_build_id(dso->long_name, &dso->bid) > 0) 553 dso->has_build_id = true; 554 nsinfo__mountns_exit(&nsc); 555 556 return dso->has_build_id ? 0 : -1; 557 } 558 559 static int dso__inject_build_id(struct dso *dso, struct perf_tool *tool, 560 struct machine *machine, u8 cpumode, u32 flags) 561 { 562 int err; 563 564 if (is_anon_memory(dso->long_name) || flags & MAP_HUGETLB) 565 return 0; 566 if (is_no_dso_memory(dso->long_name)) 567 return 0; 568 569 if (dso__read_build_id(dso) < 0) { 570 pr_debug("no build_id found for %s\n", dso->long_name); 571 return -1; 572 } 573 574 err = perf_event__synthesize_build_id(tool, dso, cpumode, 575 perf_event__repipe, machine); 576 if (err) { 577 pr_err("Can't synthesize build_id event for %s\n", dso->long_name); 578 return -1; 579 } 580 581 return 0; 582 } 583 584 int perf_event__inject_buildid(struct perf_tool *tool, union perf_event *event, 585 struct perf_sample *sample, 586 struct evsel *evsel __maybe_unused, 587 struct machine *machine) 588 { 589 struct addr_location al; 590 struct thread *thread; 591 592 thread = machine__findnew_thread(machine, sample->pid, sample->tid); 593 if (thread == NULL) { 594 pr_err("problem processing %d event, skipping it.\n", 595 event->header.type); 596 goto repipe; 597 } 598 599 if (thread__find_map(thread, sample->cpumode, sample->ip, &al)) { 600 if (!al.map->dso->hit) { 601 al.map->dso->hit = 1; 602 dso__inject_build_id(al.map->dso, tool, machine, 603 sample->cpumode, al.map->flags); 604 } 605 } 606 607 thread__put(thread); 608 repipe: 609 perf_event__repipe(tool, event, sample, machine); 610 return 0; 611 } 612 613 static int perf_inject__sched_process_exit(struct perf_tool *tool, 614 union perf_event *event __maybe_unused, 615 struct perf_sample *sample, 616 struct evsel *evsel __maybe_unused, 617 struct machine *machine __maybe_unused) 618 { 619 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 620 struct event_entry *ent; 621 622 list_for_each_entry(ent, &inject->samples, node) { 623 if (sample->tid == ent->tid) { 624 list_del_init(&ent->node); 625 free(ent); 626 break; 627 } 628 } 629 630 return 0; 631 } 632 633 static int perf_inject__sched_switch(struct perf_tool *tool, 634 union perf_event *event, 635 struct perf_sample *sample, 636 struct evsel *evsel, 637 struct machine *machine) 638 { 639 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 640 struct event_entry *ent; 641 642 perf_inject__sched_process_exit(tool, event, sample, evsel, machine); 643 644 ent = malloc(event->header.size + sizeof(struct event_entry)); 645 if (ent == NULL) { 646 color_fprintf(stderr, PERF_COLOR_RED, 647 "Not enough memory to process sched switch event!"); 648 return -1; 649 } 650 651 ent->tid = sample->tid; 652 memcpy(&ent->event, event, event->header.size); 653 list_add(&ent->node, &inject->samples); 654 return 0; 655 } 656 657 static int perf_inject__sched_stat(struct perf_tool *tool, 658 union perf_event *event __maybe_unused, 659 struct perf_sample *sample, 660 struct evsel *evsel, 661 struct machine *machine) 662 { 663 struct event_entry *ent; 664 union perf_event *event_sw; 665 struct perf_sample sample_sw; 666 struct perf_inject *inject = container_of(tool, struct perf_inject, tool); 667 u32 pid = evsel__intval(evsel, sample, "pid"); 668 669 list_for_each_entry(ent, &inject->samples, node) { 670 if (pid == ent->tid) 671 goto found; 672 } 673 674 return 0; 675 found: 676 event_sw = &ent->event[0]; 677 evsel__parse_sample(evsel, event_sw, &sample_sw); 678 679 sample_sw.period = sample->period; 680 sample_sw.time = sample->time; 681 perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type, 682 evsel->core.attr.read_format, &sample_sw); 683 build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine); 684 return perf_event__repipe(tool, event_sw, &sample_sw, machine); 685 } 686 687 static void sig_handler(int sig __maybe_unused) 688 { 689 session_done = 1; 690 } 691 692 static int evsel__check_stype(struct evsel *evsel, u64 sample_type, const char *sample_msg) 693 { 694 struct perf_event_attr *attr = &evsel->core.attr; 695 const char *name = evsel__name(evsel); 696 697 if (!(attr->sample_type & sample_type)) { 698 pr_err("Samples for %s event do not have %s attribute set.", 699 name, sample_msg); 700 return -EINVAL; 701 } 702 703 return 0; 704 } 705 706 static int drop_sample(struct perf_tool *tool __maybe_unused, 707 union perf_event *event __maybe_unused, 708 struct perf_sample *sample __maybe_unused, 709 struct evsel *evsel __maybe_unused, 710 struct machine *machine __maybe_unused) 711 { 712 return 0; 713 } 714 715 static void strip_init(struct perf_inject *inject) 716 { 717 struct evlist *evlist = inject->session->evlist; 718 struct evsel *evsel; 719 720 inject->tool.context_switch = perf_event__drop; 721 722 evlist__for_each_entry(evlist, evsel) 723 evsel->handler = drop_sample; 724 } 725 726 static int parse_vm_time_correlation(const struct option *opt, const char *str, int unset) 727 { 728 struct perf_inject *inject = opt->value; 729 const char *args; 730 char *dry_run; 731 732 if (unset) 733 return 0; 734 735 inject->itrace_synth_opts.set = true; 736 inject->itrace_synth_opts.vm_time_correlation = true; 737 inject->in_place_update = true; 738 739 if (!str) 740 return 0; 741 742 dry_run = skip_spaces(str); 743 if (!strncmp(dry_run, "dry-run", strlen("dry-run"))) { 744 inject->itrace_synth_opts.vm_tm_corr_dry_run = true; 745 inject->in_place_update_dry_run = true; 746 args = dry_run + strlen("dry-run"); 747 } else { 748 args = str; 749 } 750 751 inject->itrace_synth_opts.vm_tm_corr_args = strdup(args); 752 753 return inject->itrace_synth_opts.vm_tm_corr_args ? 0 : -ENOMEM; 754 } 755 756 static int __cmd_inject(struct perf_inject *inject) 757 { 758 int ret = -EINVAL; 759 struct perf_session *session = inject->session; 760 struct perf_data *data_out = &inject->output; 761 int fd = inject->in_place_update ? -1 : perf_data__fd(data_out); 762 u64 output_data_offset; 763 764 signal(SIGINT, sig_handler); 765 766 if (inject->build_ids || inject->sched_stat || 767 inject->itrace_synth_opts.set || inject->build_id_all) { 768 inject->tool.mmap = perf_event__repipe_mmap; 769 inject->tool.mmap2 = perf_event__repipe_mmap2; 770 inject->tool.fork = perf_event__repipe_fork; 771 inject->tool.tracing_data = perf_event__repipe_tracing_data; 772 } 773 774 output_data_offset = session->header.data_offset; 775 776 if (inject->build_id_all) { 777 inject->tool.mmap = perf_event__repipe_buildid_mmap; 778 inject->tool.mmap2 = perf_event__repipe_buildid_mmap2; 779 } else if (inject->build_ids) { 780 inject->tool.sample = perf_event__inject_buildid; 781 } else if (inject->sched_stat) { 782 struct evsel *evsel; 783 784 evlist__for_each_entry(session->evlist, evsel) { 785 const char *name = evsel__name(evsel); 786 787 if (!strcmp(name, "sched:sched_switch")) { 788 if (evsel__check_stype(evsel, PERF_SAMPLE_TID, "TID")) 789 return -EINVAL; 790 791 evsel->handler = perf_inject__sched_switch; 792 } else if (!strcmp(name, "sched:sched_process_exit")) 793 evsel->handler = perf_inject__sched_process_exit; 794 else if (!strncmp(name, "sched:sched_stat_", 17)) 795 evsel->handler = perf_inject__sched_stat; 796 } 797 } else if (inject->itrace_synth_opts.vm_time_correlation) { 798 session->itrace_synth_opts = &inject->itrace_synth_opts; 799 memset(&inject->tool, 0, sizeof(inject->tool)); 800 inject->tool.id_index = perf_event__process_id_index; 801 inject->tool.auxtrace_info = perf_event__process_auxtrace_info; 802 inject->tool.auxtrace = perf_event__process_auxtrace; 803 inject->tool.auxtrace_error = perf_event__process_auxtrace_error; 804 inject->tool.ordered_events = true; 805 inject->tool.ordering_requires_timestamps = true; 806 } else if (inject->itrace_synth_opts.set) { 807 session->itrace_synth_opts = &inject->itrace_synth_opts; 808 inject->itrace_synth_opts.inject = true; 809 inject->tool.comm = perf_event__repipe_comm; 810 inject->tool.namespaces = perf_event__repipe_namespaces; 811 inject->tool.exit = perf_event__repipe_exit; 812 inject->tool.id_index = perf_event__process_id_index; 813 inject->tool.auxtrace_info = perf_event__process_auxtrace_info; 814 inject->tool.auxtrace = perf_event__process_auxtrace; 815 inject->tool.aux = perf_event__drop_aux; 816 inject->tool.itrace_start = perf_event__drop_aux, 817 inject->tool.ordered_events = true; 818 inject->tool.ordering_requires_timestamps = true; 819 /* Allow space in the header for new attributes */ 820 output_data_offset = 4096; 821 if (inject->strip) 822 strip_init(inject); 823 } 824 825 if (!inject->itrace_synth_opts.set) 826 auxtrace_index__free(&session->auxtrace_index); 827 828 if (!data_out->is_pipe && !inject->in_place_update) 829 lseek(fd, output_data_offset, SEEK_SET); 830 831 ret = perf_session__process_events(session); 832 if (ret) 833 return ret; 834 835 if (!data_out->is_pipe && !inject->in_place_update) { 836 if (inject->build_ids) 837 perf_header__set_feat(&session->header, 838 HEADER_BUILD_ID); 839 /* 840 * Keep all buildids when there is unprocessed AUX data because 841 * it is not known which ones the AUX trace hits. 842 */ 843 if (perf_header__has_feat(&session->header, HEADER_BUILD_ID) && 844 inject->have_auxtrace && !inject->itrace_synth_opts.set) 845 dsos__hit_all(session); 846 /* 847 * The AUX areas have been removed and replaced with 848 * synthesized hardware events, so clear the feature flag. 849 */ 850 if (inject->itrace_synth_opts.set) { 851 perf_header__clear_feat(&session->header, 852 HEADER_AUXTRACE); 853 if (inject->itrace_synth_opts.last_branch || 854 inject->itrace_synth_opts.add_last_branch) 855 perf_header__set_feat(&session->header, 856 HEADER_BRANCH_STACK); 857 } 858 session->header.data_offset = output_data_offset; 859 session->header.data_size = inject->bytes_written; 860 perf_session__write_header(session, session->evlist, fd, true); 861 } 862 863 return ret; 864 } 865 866 int cmd_inject(int argc, const char **argv) 867 { 868 struct perf_inject inject = { 869 .tool = { 870 .sample = perf_event__repipe_sample, 871 .read = perf_event__repipe_sample, 872 .mmap = perf_event__repipe, 873 .mmap2 = perf_event__repipe, 874 .comm = perf_event__repipe, 875 .namespaces = perf_event__repipe, 876 .cgroup = perf_event__repipe, 877 .fork = perf_event__repipe, 878 .exit = perf_event__repipe, 879 .lost = perf_event__repipe, 880 .lost_samples = perf_event__repipe, 881 .aux = perf_event__repipe, 882 .itrace_start = perf_event__repipe, 883 .context_switch = perf_event__repipe, 884 .throttle = perf_event__repipe, 885 .unthrottle = perf_event__repipe, 886 .ksymbol = perf_event__repipe, 887 .bpf = perf_event__repipe, 888 .text_poke = perf_event__repipe, 889 .attr = perf_event__repipe_attr, 890 .event_update = perf_event__repipe_event_update, 891 .tracing_data = perf_event__repipe_op2_synth, 892 .finished_round = perf_event__repipe_oe_synth, 893 .build_id = perf_event__repipe_op2_synth, 894 .id_index = perf_event__repipe_op2_synth, 895 .auxtrace_info = perf_event__repipe_op2_synth, 896 .auxtrace_error = perf_event__repipe_op2_synth, 897 .time_conv = perf_event__repipe_op2_synth, 898 .thread_map = perf_event__repipe_op2_synth, 899 .cpu_map = perf_event__repipe_op2_synth, 900 .stat_config = perf_event__repipe_op2_synth, 901 .stat = perf_event__repipe_op2_synth, 902 .stat_round = perf_event__repipe_op2_synth, 903 .feature = perf_event__repipe_op2_synth, 904 .compressed = perf_event__repipe_op4_synth, 905 .auxtrace = perf_event__repipe_auxtrace, 906 }, 907 .input_name = "-", 908 .samples = LIST_HEAD_INIT(inject.samples), 909 .output = { 910 .path = "-", 911 .mode = PERF_DATA_MODE_WRITE, 912 .use_stdio = true, 913 }, 914 }; 915 struct perf_data data = { 916 .mode = PERF_DATA_MODE_READ, 917 .use_stdio = true, 918 }; 919 int ret; 920 921 struct option options[] = { 922 OPT_BOOLEAN('b', "build-ids", &inject.build_ids, 923 "Inject build-ids into the output stream"), 924 OPT_BOOLEAN(0, "buildid-all", &inject.build_id_all, 925 "Inject build-ids of all DSOs into the output stream"), 926 OPT_STRING('i', "input", &inject.input_name, "file", 927 "input file name"), 928 OPT_STRING('o', "output", &inject.output.path, "file", 929 "output file name"), 930 OPT_BOOLEAN('s', "sched-stat", &inject.sched_stat, 931 "Merge sched-stat and sched-switch for getting events " 932 "where and how long tasks slept"), 933 #ifdef HAVE_JITDUMP 934 OPT_BOOLEAN('j', "jit", &inject.jit_mode, "merge jitdump files into perf.data file"), 935 #endif 936 OPT_INCR('v', "verbose", &verbose, 937 "be more verbose (show build ids, etc)"), 938 OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name, "file", 939 "kallsyms pathname"), 940 OPT_BOOLEAN('f', "force", &data.force, "don't complain, do it"), 941 OPT_CALLBACK_OPTARG(0, "itrace", &inject.itrace_synth_opts, 942 NULL, "opts", "Instruction Tracing options\n" 943 ITRACE_HELP, 944 itrace_parse_synth_opts), 945 OPT_BOOLEAN(0, "strip", &inject.strip, 946 "strip non-synthesized events (use with --itrace)"), 947 OPT_CALLBACK_OPTARG(0, "vm-time-correlation", &inject, NULL, "opts", 948 "correlate time between VM guests and the host", 949 parse_vm_time_correlation), 950 OPT_END() 951 }; 952 const char * const inject_usage[] = { 953 "perf inject [<options>]", 954 NULL 955 }; 956 #ifndef HAVE_JITDUMP 957 set_option_nobuild(options, 'j', "jit", "NO_LIBELF=1", true); 958 #endif 959 argc = parse_options(argc, argv, options, inject_usage, 0); 960 961 /* 962 * Any (unrecognized) arguments left? 963 */ 964 if (argc) 965 usage_with_options(inject_usage, options); 966 967 if (inject.strip && !inject.itrace_synth_opts.set) { 968 pr_err("--strip option requires --itrace option\n"); 969 return -1; 970 } 971 972 if (inject.in_place_update) { 973 if (!strcmp(inject.input_name, "-")) { 974 pr_err("Input file name required for in-place updating\n"); 975 return -1; 976 } 977 if (strcmp(inject.output.path, "-")) { 978 pr_err("Output file name must not be specified for in-place updating\n"); 979 return -1; 980 } 981 if (!data.force && !inject.in_place_update_dry_run) { 982 pr_err("The input file would be updated in place, " 983 "the --force option is required.\n"); 984 return -1; 985 } 986 if (!inject.in_place_update_dry_run) 987 data.in_place_update = true; 988 } else if (perf_data__open(&inject.output)) { 989 perror("failed to create output file"); 990 return -1; 991 } 992 993 data.path = inject.input_name; 994 inject.session = perf_session__new(&data, inject.output.is_pipe, &inject.tool); 995 if (IS_ERR(inject.session)) 996 return PTR_ERR(inject.session); 997 998 if (zstd_init(&(inject.session->zstd_data), 0) < 0) 999 pr_warning("Decompression initialization failed.\n"); 1000 1001 if (inject.build_ids && !inject.build_id_all) { 1002 /* 1003 * to make sure the mmap records are ordered correctly 1004 * and so that the correct especially due to jitted code 1005 * mmaps. We cannot generate the buildid hit list and 1006 * inject the jit mmaps at the same time for now. 1007 */ 1008 inject.tool.ordered_events = true; 1009 inject.tool.ordering_requires_timestamps = true; 1010 } 1011 1012 if (inject.sched_stat) { 1013 inject.tool.ordered_events = true; 1014 } 1015 1016 #ifdef HAVE_JITDUMP 1017 if (inject.jit_mode) { 1018 inject.tool.mmap2 = perf_event__jit_repipe_mmap2; 1019 inject.tool.mmap = perf_event__jit_repipe_mmap; 1020 inject.tool.ordered_events = true; 1021 inject.tool.ordering_requires_timestamps = true; 1022 /* 1023 * JIT MMAP injection injects all MMAP events in one go, so it 1024 * does not obey finished_round semantics. 1025 */ 1026 inject.tool.finished_round = perf_event__drop_oe; 1027 } 1028 #endif 1029 ret = symbol__init(&inject.session->header.env); 1030 if (ret < 0) 1031 goto out_delete; 1032 1033 ret = __cmd_inject(&inject); 1034 1035 out_delete: 1036 zstd_fini(&(inject.session->zstd_data)); 1037 perf_session__delete(inject.session); 1038 free(inject.itrace_synth_opts.vm_tm_corr_args); 1039 return ret; 1040 } 1041