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