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