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