2510 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3#include "util/cgroup.h"4#include "util/data.h"5#include "util/debug.h"6#include "util/dso.h"7#include "util/event.h"8#include "util/evlist.h"9#include "util/machine.h"10#include "util/map.h"11#include "util/map_symbol.h"12#include "util/branch.h"13#include "util/memswap.h"14#include "util/namespaces.h"15#include "util/session.h"16#include "util/stat.h"17#include "util/symbol.h"18#include "util/synthetic-events.h"19#include "util/target.h"20#include "util/time-utils.h"21#include <linux/bitops.h>22#include <linux/kernel.h>23#include <linux/string.h>24#include <linux/zalloc.h>25#include <linux/perf_event.h>26#include <asm/bug.h>27#include <perf/evsel.h>28#include <perf/cpumap.h>29#include <internal/lib.h> // page_size30#include <internal/threadmap.h>31#include <perf/threadmap.h>32#include <symbol/kallsyms.h>33#include <dirent.h>34#include <errno.h>35#include <inttypes.h>36#include <stdio.h>37#include <string.h>38#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */39#include <api/fs/fs.h>40#include <api/io.h>41#include <sys/types.h>42#include <sys/stat.h>43#include <fcntl.h>44#include <unistd.h>45 46#define DEFAULT_PROC_MAP_PARSE_TIMEOUT 50047 48unsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT;49 50int perf_tool__process_synth_event(const struct perf_tool *tool,51 union perf_event *event,52 struct machine *machine,53 perf_event__handler_t process)54{55 struct perf_sample synth_sample = {56 .pid = -1,57 .tid = -1,58 .time = -1,59 .stream_id = -1,60 .cpu = -1,61 .period = 1,62 .cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK,63 };64 65 return process(tool, event, &synth_sample, machine);66};67 68/*69 * Assumes that the first 4095 bytes of /proc/pid/stat contains70 * the comm, tgid and ppid.71 */72static int perf_event__get_comm_ids(pid_t pid, pid_t tid, char *comm, size_t len,73 pid_t *tgid, pid_t *ppid, bool *kernel)74{75 char bf[4096];76 int fd;77 size_t size = 0;78 ssize_t n;79 char *name, *tgids, *ppids, *vmpeak, *threads;80 81 *tgid = -1;82 *ppid = -1;83 84 if (pid)85 snprintf(bf, sizeof(bf), "/proc/%d/task/%d/status", pid, tid);86 else87 snprintf(bf, sizeof(bf), "/proc/%d/status", tid);88 89 fd = open(bf, O_RDONLY);90 if (fd < 0) {91 pr_debug("couldn't open %s\n", bf);92 return -1;93 }94 95 n = read(fd, bf, sizeof(bf) - 1);96 close(fd);97 if (n <= 0) {98 pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n",99 tid);100 return -1;101 }102 bf[n] = '\0';103 104 name = strstr(bf, "Name:");105 tgids = strstr(name ?: bf, "Tgid:");106 ppids = strstr(tgids ?: bf, "PPid:");107 vmpeak = strstr(ppids ?: bf, "VmPeak:");108 109 if (vmpeak)110 threads = NULL;111 else112 threads = strstr(ppids ?: bf, "Threads:");113 114 if (name) {115 char *nl;116 117 name = skip_spaces(name + 5); /* strlen("Name:") */118 nl = strchr(name, '\n');119 if (nl)120 *nl = '\0';121 122 size = strlen(name);123 if (size >= len)124 size = len - 1;125 memcpy(comm, name, size);126 comm[size] = '\0';127 } else {128 pr_debug("Name: string not found for pid %d\n", tid);129 }130 131 if (tgids) {132 tgids += 5; /* strlen("Tgid:") */133 *tgid = atoi(tgids);134 } else {135 pr_debug("Tgid: string not found for pid %d\n", tid);136 }137 138 if (ppids) {139 ppids += 5; /* strlen("PPid:") */140 *ppid = atoi(ppids);141 } else {142 pr_debug("PPid: string not found for pid %d\n", tid);143 }144 145 if (!vmpeak && threads)146 *kernel = true;147 else148 *kernel = false;149 150 return 0;151}152 153static int perf_event__prepare_comm(union perf_event *event, pid_t pid, pid_t tid,154 struct machine *machine,155 pid_t *tgid, pid_t *ppid, bool *kernel)156{157 size_t size;158 159 *ppid = -1;160 161 memset(&event->comm, 0, sizeof(event->comm));162 163 if (machine__is_host(machine)) {164 if (perf_event__get_comm_ids(pid, tid, event->comm.comm,165 sizeof(event->comm.comm),166 tgid, ppid, kernel) != 0) {167 return -1;168 }169 } else {170 *tgid = machine->pid;171 }172 173 if (*tgid < 0)174 return -1;175 176 event->comm.pid = *tgid;177 event->comm.header.type = PERF_RECORD_COMM;178 179 size = strlen(event->comm.comm) + 1;180 size = PERF_ALIGN(size, sizeof(u64));181 memset(event->comm.comm + size, 0, machine->id_hdr_size);182 event->comm.header.size = (sizeof(event->comm) -183 (sizeof(event->comm.comm) - size) +184 machine->id_hdr_size);185 event->comm.tid = tid;186 187 return 0;188}189 190pid_t perf_event__synthesize_comm(const struct perf_tool *tool,191 union perf_event *event, pid_t pid,192 perf_event__handler_t process,193 struct machine *machine)194{195 pid_t tgid, ppid;196 bool kernel_thread;197 198 if (perf_event__prepare_comm(event, 0, pid, machine, &tgid, &ppid,199 &kernel_thread) != 0)200 return -1;201 202 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)203 return -1;204 205 return tgid;206}207 208static void perf_event__get_ns_link_info(pid_t pid, const char *ns,209 struct perf_ns_link_info *ns_link_info)210{211 struct stat64 st;212 char proc_ns[128];213 214 sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);215 if (stat64(proc_ns, &st) == 0) {216 ns_link_info->dev = st.st_dev;217 ns_link_info->ino = st.st_ino;218 }219}220 221int perf_event__synthesize_namespaces(const struct perf_tool *tool,222 union perf_event *event,223 pid_t pid, pid_t tgid,224 perf_event__handler_t process,225 struct machine *machine)226{227 u32 idx;228 struct perf_ns_link_info *ns_link_info;229 230 if (!tool || !tool->namespace_events)231 return 0;232 233 memset(&event->namespaces, 0, (sizeof(event->namespaces) +234 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +235 machine->id_hdr_size));236 237 event->namespaces.pid = tgid;238 event->namespaces.tid = pid;239 240 event->namespaces.nr_namespaces = NR_NAMESPACES;241 242 ns_link_info = event->namespaces.link_info;243 244 for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)245 perf_event__get_ns_link_info(pid, perf_ns__name(idx),246 &ns_link_info[idx]);247 248 event->namespaces.header.type = PERF_RECORD_NAMESPACES;249 250 event->namespaces.header.size = (sizeof(event->namespaces) +251 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +252 machine->id_hdr_size);253 254 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)255 return -1;256 257 return 0;258}259 260static int perf_event__synthesize_fork(const struct perf_tool *tool,261 union perf_event *event,262 pid_t pid, pid_t tgid, pid_t ppid,263 perf_event__handler_t process,264 struct machine *machine)265{266 memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);267 268 /*269 * for main thread set parent to ppid from status file. For other270 * threads set parent pid to main thread. ie., assume main thread271 * spawns all threads in a process272 */273 if (tgid == pid) {274 event->fork.ppid = ppid;275 event->fork.ptid = ppid;276 } else {277 event->fork.ppid = tgid;278 event->fork.ptid = tgid;279 }280 event->fork.pid = tgid;281 event->fork.tid = pid;282 event->fork.header.type = PERF_RECORD_FORK;283 event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC;284 285 event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);286 287 if (perf_tool__process_synth_event(tool, event, machine, process) != 0)288 return -1;289 290 return 0;291}292 293static bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end,294 u32 *prot, u32 *flags, __u64 *offset,295 u32 *maj, u32 *min,296 __u64 *inode,297 ssize_t pathname_size, char *pathname)298{299 __u64 temp;300 int ch;301 char *start_pathname = pathname;302 303 if (io__get_hex(io, start) != '-')304 return false;305 if (io__get_hex(io, end) != ' ')306 return false;307 308 /* map protection and flags bits */309 *prot = 0;310 ch = io__get_char(io);311 if (ch == 'r')312 *prot |= PROT_READ;313 else if (ch != '-')314 return false;315 ch = io__get_char(io);316 if (ch == 'w')317 *prot |= PROT_WRITE;318 else if (ch != '-')319 return false;320 ch = io__get_char(io);321 if (ch == 'x')322 *prot |= PROT_EXEC;323 else if (ch != '-')324 return false;325 ch = io__get_char(io);326 if (ch == 's')327 *flags = MAP_SHARED;328 else if (ch == 'p')329 *flags = MAP_PRIVATE;330 else331 return false;332 if (io__get_char(io) != ' ')333 return false;334 335 if (io__get_hex(io, offset) != ' ')336 return false;337 338 if (io__get_hex(io, &temp) != ':')339 return false;340 *maj = temp;341 if (io__get_hex(io, &temp) != ' ')342 return false;343 *min = temp;344 345 ch = io__get_dec(io, inode);346 if (ch != ' ') {347 *pathname = '\0';348 return ch == '\n';349 }350 do {351 ch = io__get_char(io);352 } while (ch == ' ');353 while (true) {354 if (ch < 0)355 return false;356 if (ch == '\0' || ch == '\n' ||357 (pathname + 1 - start_pathname) >= pathname_size) {358 *pathname = '\0';359 return true;360 }361 *pathname++ = ch;362 ch = io__get_char(io);363 }364}365 366static void perf_record_mmap2__read_build_id(struct perf_record_mmap2 *event,367 struct machine *machine,368 bool is_kernel)369{370 struct build_id bid;371 struct nsinfo *nsi;372 struct nscookie nc;373 struct dso *dso = NULL;374 struct dso_id id;375 int rc;376 377 if (is_kernel) {378 rc = sysfs__read_build_id("/sys/kernel/notes", &bid);379 goto out;380 }381 382 id.maj = event->maj;383 id.min = event->min;384 id.ino = event->ino;385 id.ino_generation = event->ino_generation;386 387 dso = dsos__findnew_id(&machine->dsos, event->filename, &id);388 if (dso && dso__has_build_id(dso)) {389 bid = *dso__bid(dso);390 rc = 0;391 goto out;392 }393 394 nsi = nsinfo__new(event->pid);395 nsinfo__mountns_enter(nsi, &nc);396 397 rc = filename__read_build_id(event->filename, &bid) > 0 ? 0 : -1;398 399 nsinfo__mountns_exit(&nc);400 nsinfo__put(nsi);401 402out:403 if (rc == 0) {404 memcpy(event->build_id, bid.data, sizeof(bid.data));405 event->build_id_size = (u8) bid.size;406 event->header.misc |= PERF_RECORD_MISC_MMAP_BUILD_ID;407 event->__reserved_1 = 0;408 event->__reserved_2 = 0;409 410 if (dso && !dso__has_build_id(dso))411 dso__set_build_id(dso, &bid);412 } else {413 if (event->filename[0] == '/') {414 pr_debug2("Failed to read build ID for %s\n",415 event->filename);416 }417 }418 dso__put(dso);419}420 421int perf_event__synthesize_mmap_events(const struct perf_tool *tool,422 union perf_event *event,423 pid_t pid, pid_t tgid,424 perf_event__handler_t process,425 struct machine *machine,426 bool mmap_data)427{428 unsigned long long t;429 char bf[BUFSIZ];430 struct io io;431 bool truncation = false;432 unsigned long long timeout = proc_map_timeout * 1000000ULL;433 int rc = 0;434 const char *hugetlbfs_mnt = hugetlbfs__mountpoint();435 int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0;436 437 if (machine__is_default_guest(machine))438 return 0;439 440 snprintf(bf, sizeof(bf), "%s/proc/%d/task/%d/maps",441 machine->root_dir, pid, pid);442 443 io.fd = open(bf, O_RDONLY, 0);444 if (io.fd < 0) {445 /*446 * We raced with a task exiting - just return:447 */448 pr_debug("couldn't open %s\n", bf);449 return -1;450 }451 io__init(&io, io.fd, bf, sizeof(bf));452 453 event->header.type = PERF_RECORD_MMAP2;454 t = rdclock();455 456 while (!io.eof) {457 static const char anonstr[] = "//anon";458 size_t size, aligned_size;459 460 /* ensure null termination since stack will be reused. */461 event->mmap2.filename[0] = '\0';462 463 /* 00400000-0040c000 r-xp 00000000 fd:01 41038 /bin/cat */464 if (!read_proc_maps_line(&io,465 &event->mmap2.start,466 &event->mmap2.len,467 &event->mmap2.prot,468 &event->mmap2.flags,469 &event->mmap2.pgoff,470 &event->mmap2.maj,471 &event->mmap2.min,472 &event->mmap2.ino,473 sizeof(event->mmap2.filename),474 event->mmap2.filename))475 continue;476 477 if ((rdclock() - t) > timeout) {478 pr_warning("Reading %s/proc/%d/task/%d/maps time out. "479 "You may want to increase "480 "the time limit by --proc-map-timeout\n",481 machine->root_dir, pid, pid);482 truncation = true;483 goto out;484 }485 486 event->mmap2.ino_generation = 0;487 488 /*489 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c490 */491 if (machine__is_host(machine))492 event->header.misc = PERF_RECORD_MISC_USER;493 else494 event->header.misc = PERF_RECORD_MISC_GUEST_USER;495 496 if ((event->mmap2.prot & PROT_EXEC) == 0) {497 if (!mmap_data || (event->mmap2.prot & PROT_READ) == 0)498 continue;499 500 event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;501 }502 503out:504 if (truncation)505 event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT;506 507 if (!strcmp(event->mmap2.filename, ""))508 strcpy(event->mmap2.filename, anonstr);509 510 if (hugetlbfs_mnt_len &&511 !strncmp(event->mmap2.filename, hugetlbfs_mnt,512 hugetlbfs_mnt_len)) {513 strcpy(event->mmap2.filename, anonstr);514 event->mmap2.flags |= MAP_HUGETLB;515 }516 517 size = strlen(event->mmap2.filename) + 1;518 aligned_size = PERF_ALIGN(size, sizeof(u64));519 event->mmap2.len -= event->mmap.start;520 event->mmap2.header.size = (sizeof(event->mmap2) -521 (sizeof(event->mmap2.filename) - aligned_size));522 memset(event->mmap2.filename + size, 0, machine->id_hdr_size +523 (aligned_size - size));524 event->mmap2.header.size += machine->id_hdr_size;525 event->mmap2.pid = tgid;526 event->mmap2.tid = pid;527 528 if (symbol_conf.buildid_mmap2)529 perf_record_mmap2__read_build_id(&event->mmap2, machine, false);530 531 if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {532 rc = -1;533 break;534 }535 536 if (truncation)537 break;538 }539 540 close(io.fd);541 return rc;542}543 544#ifdef HAVE_FILE_HANDLE545static int perf_event__synthesize_cgroup(const struct perf_tool *tool,546 union perf_event *event,547 char *path, size_t mount_len,548 perf_event__handler_t process,549 struct machine *machine)550{551 size_t event_size = sizeof(event->cgroup) - sizeof(event->cgroup.path);552 size_t path_len = strlen(path) - mount_len + 1;553 struct {554 struct file_handle fh;555 uint64_t cgroup_id;556 } handle;557 int mount_id;558 559 while (path_len % sizeof(u64))560 path[mount_len + path_len++] = '\0';561 562 memset(&event->cgroup, 0, event_size);563 564 event->cgroup.header.type = PERF_RECORD_CGROUP;565 event->cgroup.header.size = event_size + path_len + machine->id_hdr_size;566 567 handle.fh.handle_bytes = sizeof(handle.cgroup_id);568 if (name_to_handle_at(AT_FDCWD, path, &handle.fh, &mount_id, 0) < 0) {569 pr_debug("stat failed: %s\n", path);570 return -1;571 }572 573 event->cgroup.id = handle.cgroup_id;574 strncpy(event->cgroup.path, path + mount_len, path_len);575 memset(event->cgroup.path + path_len, 0, machine->id_hdr_size);576 577 if (perf_tool__process_synth_event(tool, event, machine, process) < 0) {578 pr_debug("process synth event failed\n");579 return -1;580 }581 582 return 0;583}584 585static int perf_event__walk_cgroup_tree(const struct perf_tool *tool,586 union perf_event *event,587 char *path, size_t mount_len,588 perf_event__handler_t process,589 struct machine *machine)590{591 size_t pos = strlen(path);592 DIR *d;593 struct dirent *dent;594 int ret = 0;595 596 if (perf_event__synthesize_cgroup(tool, event, path, mount_len,597 process, machine) < 0)598 return -1;599 600 d = opendir(path);601 if (d == NULL) {602 pr_debug("failed to open directory: %s\n", path);603 return -1;604 }605 606 while ((dent = readdir(d)) != NULL) {607 if (dent->d_type != DT_DIR)608 continue;609 if (!strcmp(dent->d_name, ".") ||610 !strcmp(dent->d_name, ".."))611 continue;612 613 /* any sane path should be less than PATH_MAX */614 if (strlen(path) + strlen(dent->d_name) + 1 >= PATH_MAX)615 continue;616 617 if (path[pos - 1] != '/')618 strcat(path, "/");619 strcat(path, dent->d_name);620 621 ret = perf_event__walk_cgroup_tree(tool, event, path,622 mount_len, process, machine);623 if (ret < 0)624 break;625 626 path[pos] = '\0';627 }628 629 closedir(d);630 return ret;631}632 633int perf_event__synthesize_cgroups(const struct perf_tool *tool,634 perf_event__handler_t process,635 struct machine *machine)636{637 union perf_event event;638 char cgrp_root[PATH_MAX];639 size_t mount_len; /* length of mount point in the path */640 641 if (!tool || !tool->cgroup_events)642 return 0;643 644 if (cgroupfs_find_mountpoint(cgrp_root, PATH_MAX, "perf_event") < 0) {645 pr_debug("cannot find cgroup mount point\n");646 return -1;647 }648 649 mount_len = strlen(cgrp_root);650 /* make sure the path starts with a slash (after mount point) */651 strcat(cgrp_root, "/");652 653 if (perf_event__walk_cgroup_tree(tool, &event, cgrp_root, mount_len,654 process, machine) < 0)655 return -1;656 657 return 0;658}659#else660int perf_event__synthesize_cgroups(const struct perf_tool *tool __maybe_unused,661 perf_event__handler_t process __maybe_unused,662 struct machine *machine __maybe_unused)663{664 return -1;665}666#endif667 668struct perf_event__synthesize_modules_maps_cb_args {669 const struct perf_tool *tool;670 perf_event__handler_t process;671 struct machine *machine;672 union perf_event *event;673};674 675static int perf_event__synthesize_modules_maps_cb(struct map *map, void *data)676{677 struct perf_event__synthesize_modules_maps_cb_args *args = data;678 union perf_event *event = args->event;679 struct dso *dso;680 size_t size;681 682 if (!__map__is_kmodule(map))683 return 0;684 685 dso = map__dso(map);686 if (symbol_conf.buildid_mmap2) {687 size = PERF_ALIGN(dso__long_name_len(dso) + 1, sizeof(u64));688 event->mmap2.header.type = PERF_RECORD_MMAP2;689 event->mmap2.header.size = (sizeof(event->mmap2) -690 (sizeof(event->mmap2.filename) - size));691 memset(event->mmap2.filename + size, 0, args->machine->id_hdr_size);692 event->mmap2.header.size += args->machine->id_hdr_size;693 event->mmap2.start = map__start(map);694 event->mmap2.len = map__size(map);695 event->mmap2.pid = args->machine->pid;696 697 memcpy(event->mmap2.filename, dso__long_name(dso), dso__long_name_len(dso) + 1);698 699 perf_record_mmap2__read_build_id(&event->mmap2, args->machine, false);700 } else {701 size = PERF_ALIGN(dso__long_name_len(dso) + 1, sizeof(u64));702 event->mmap.header.type = PERF_RECORD_MMAP;703 event->mmap.header.size = (sizeof(event->mmap) -704 (sizeof(event->mmap.filename) - size));705 memset(event->mmap.filename + size, 0, args->machine->id_hdr_size);706 event->mmap.header.size += args->machine->id_hdr_size;707 event->mmap.start = map__start(map);708 event->mmap.len = map__size(map);709 event->mmap.pid = args->machine->pid;710 711 memcpy(event->mmap.filename, dso__long_name(dso), dso__long_name_len(dso) + 1);712 }713 714 if (perf_tool__process_synth_event(args->tool, event, args->machine, args->process) != 0)715 return -1;716 717 return 0;718}719 720int perf_event__synthesize_modules(const struct perf_tool *tool, perf_event__handler_t process,721 struct machine *machine)722{723 int rc;724 struct maps *maps = machine__kernel_maps(machine);725 struct perf_event__synthesize_modules_maps_cb_args args = {726 .tool = tool,727 .process = process,728 .machine = machine,729 };730 size_t size = symbol_conf.buildid_mmap2731 ? sizeof(args.event->mmap2)732 : sizeof(args.event->mmap);733 734 args.event = zalloc(size + machine->id_hdr_size);735 if (args.event == NULL) {736 pr_debug("Not enough memory synthesizing mmap event "737 "for kernel modules\n");738 return -1;739 }740 741 /*742 * kernel uses 0 for user space maps, see kernel/perf_event.c743 * __perf_event_mmap744 */745 if (machine__is_host(machine))746 args.event->header.misc = PERF_RECORD_MISC_KERNEL;747 else748 args.event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;749 750 rc = maps__for_each_map(maps, perf_event__synthesize_modules_maps_cb, &args);751 752 free(args.event);753 return rc;754}755 756static int filter_task(const struct dirent *dirent)757{758 return isdigit(dirent->d_name[0]);759}760 761static int __event__synthesize_thread(union perf_event *comm_event,762 union perf_event *mmap_event,763 union perf_event *fork_event,764 union perf_event *namespaces_event,765 pid_t pid, int full, perf_event__handler_t process,766 const struct perf_tool *tool, struct machine *machine,767 bool needs_mmap, bool mmap_data)768{769 char filename[PATH_MAX];770 struct dirent **dirent;771 pid_t tgid, ppid;772 int rc = 0;773 int i, n;774 775 /* special case: only send one comm event using passed in pid */776 if (!full) {777 tgid = perf_event__synthesize_comm(tool, comm_event, pid,778 process, machine);779 780 if (tgid == -1)781 return -1;782 783 if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,784 tgid, process, machine) < 0)785 return -1;786 787 /*788 * send mmap only for thread group leader789 * see thread__init_maps()790 */791 if (pid == tgid && needs_mmap &&792 perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,793 process, machine, mmap_data))794 return -1;795 796 return 0;797 }798 799 if (machine__is_default_guest(machine))800 return 0;801 802 snprintf(filename, sizeof(filename), "%s/proc/%d/task",803 machine->root_dir, pid);804 805 n = scandir(filename, &dirent, filter_task, NULL);806 if (n < 0)807 return n;808 809 for (i = 0; i < n; i++) {810 char *end;811 pid_t _pid;812 bool kernel_thread = false;813 814 _pid = strtol(dirent[i]->d_name, &end, 10);815 if (*end)816 continue;817 818 /* some threads may exit just after scan, ignore it */819 if (perf_event__prepare_comm(comm_event, pid, _pid, machine,820 &tgid, &ppid, &kernel_thread) != 0)821 continue;822 823 rc = -1;824 if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,825 ppid, process, machine) < 0)826 break;827 828 if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,829 tgid, process, machine) < 0)830 break;831 832 /*833 * Send the prepared comm event834 */835 if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0)836 break;837 838 rc = 0;839 if (_pid == pid && !kernel_thread && needs_mmap) {840 /* process the parent's maps too */841 rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,842 process, machine, mmap_data);843 if (rc)844 break;845 }846 }847 848 for (i = 0; i < n; i++)849 zfree(&dirent[i]);850 free(dirent);851 852 return rc;853}854 855int perf_event__synthesize_thread_map(const struct perf_tool *tool,856 struct perf_thread_map *threads,857 perf_event__handler_t process,858 struct machine *machine,859 bool needs_mmap, bool mmap_data)860{861 union perf_event *comm_event, *mmap_event, *fork_event;862 union perf_event *namespaces_event;863 int err = -1, thread, j;864 865 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);866 if (comm_event == NULL)867 goto out;868 869 mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);870 if (mmap_event == NULL)871 goto out_free_comm;872 873 fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);874 if (fork_event == NULL)875 goto out_free_mmap;876 877 namespaces_event = malloc(sizeof(namespaces_event->namespaces) +878 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +879 machine->id_hdr_size);880 if (namespaces_event == NULL)881 goto out_free_fork;882 883 err = 0;884 for (thread = 0; thread < threads->nr; ++thread) {885 if (__event__synthesize_thread(comm_event, mmap_event,886 fork_event, namespaces_event,887 perf_thread_map__pid(threads, thread), 0,888 process, tool, machine,889 needs_mmap, mmap_data)) {890 err = -1;891 break;892 }893 894 /*895 * comm.pid is set to thread group id by896 * perf_event__synthesize_comm897 */898 if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) {899 bool need_leader = true;900 901 /* is thread group leader in thread_map? */902 for (j = 0; j < threads->nr; ++j) {903 if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) {904 need_leader = false;905 break;906 }907 }908 909 /* if not, generate events for it */910 if (need_leader &&911 __event__synthesize_thread(comm_event, mmap_event,912 fork_event, namespaces_event,913 comm_event->comm.pid, 0,914 process, tool, machine,915 needs_mmap, mmap_data)) {916 err = -1;917 break;918 }919 }920 }921 free(namespaces_event);922out_free_fork:923 free(fork_event);924out_free_mmap:925 free(mmap_event);926out_free_comm:927 free(comm_event);928out:929 return err;930}931 932static int __perf_event__synthesize_threads(const struct perf_tool *tool,933 perf_event__handler_t process,934 struct machine *machine,935 bool needs_mmap,936 bool mmap_data,937 struct dirent **dirent,938 int start,939 int num)940{941 union perf_event *comm_event, *mmap_event, *fork_event;942 union perf_event *namespaces_event;943 int err = -1;944 char *end;945 pid_t pid;946 int i;947 948 comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);949 if (comm_event == NULL)950 goto out;951 952 mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);953 if (mmap_event == NULL)954 goto out_free_comm;955 956 fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);957 if (fork_event == NULL)958 goto out_free_mmap;959 960 namespaces_event = malloc(sizeof(namespaces_event->namespaces) +961 (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +962 machine->id_hdr_size);963 if (namespaces_event == NULL)964 goto out_free_fork;965 966 for (i = start; i < start + num; i++) {967 if (!isdigit(dirent[i]->d_name[0]))968 continue;969 970 pid = (pid_t)strtol(dirent[i]->d_name, &end, 10);971 /* only interested in proper numerical dirents */972 if (*end)973 continue;974 /*975 * We may race with exiting thread, so don't stop just because976 * one thread couldn't be synthesized.977 */978 __event__synthesize_thread(comm_event, mmap_event, fork_event,979 namespaces_event, pid, 1, process,980 tool, machine, needs_mmap, mmap_data);981 }982 err = 0;983 984 free(namespaces_event);985out_free_fork:986 free(fork_event);987out_free_mmap:988 free(mmap_event);989out_free_comm:990 free(comm_event);991out:992 return err;993}994 995struct synthesize_threads_arg {996 const struct perf_tool *tool;997 perf_event__handler_t process;998 struct machine *machine;999 bool needs_mmap;1000 bool mmap_data;1001 struct dirent **dirent;1002 int num;1003 int start;1004};1005 1006static void *synthesize_threads_worker(void *arg)1007{1008 struct synthesize_threads_arg *args = arg;1009 1010 __perf_event__synthesize_threads(args->tool, args->process,1011 args->machine,1012 args->needs_mmap, args->mmap_data,1013 args->dirent,1014 args->start, args->num);1015 return NULL;1016}1017 1018int perf_event__synthesize_threads(const struct perf_tool *tool,1019 perf_event__handler_t process,1020 struct machine *machine,1021 bool needs_mmap, bool mmap_data,1022 unsigned int nr_threads_synthesize)1023{1024 struct synthesize_threads_arg *args = NULL;1025 pthread_t *synthesize_threads = NULL;1026 char proc_path[PATH_MAX];1027 struct dirent **dirent;1028 int num_per_thread;1029 int m, n, i, j;1030 int thread_nr;1031 int base = 0;1032 int err = -1;1033 1034 1035 if (machine__is_default_guest(machine))1036 return 0;1037 1038 snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);1039 n = scandir(proc_path, &dirent, filter_task, NULL);1040 if (n < 0)1041 return err;1042 1043 if (nr_threads_synthesize == UINT_MAX)1044 thread_nr = sysconf(_SC_NPROCESSORS_ONLN);1045 else1046 thread_nr = nr_threads_synthesize;1047 1048 if (thread_nr <= 1) {1049 err = __perf_event__synthesize_threads(tool, process,1050 machine,1051 needs_mmap, mmap_data,1052 dirent, base, n);1053 goto free_dirent;1054 }1055 if (thread_nr > n)1056 thread_nr = n;1057 1058 synthesize_threads = calloc(thread_nr, sizeof(pthread_t));1059 if (synthesize_threads == NULL)1060 goto free_dirent;1061 1062 args = calloc(thread_nr, sizeof(*args));1063 if (args == NULL)1064 goto free_threads;1065 1066 num_per_thread = n / thread_nr;1067 m = n % thread_nr;1068 for (i = 0; i < thread_nr; i++) {1069 args[i].tool = tool;1070 args[i].process = process;1071 args[i].machine = machine;1072 args[i].needs_mmap = needs_mmap;1073 args[i].mmap_data = mmap_data;1074 args[i].dirent = dirent;1075 }1076 for (i = 0; i < m; i++) {1077 args[i].num = num_per_thread + 1;1078 args[i].start = i * args[i].num;1079 }1080 if (i != 0)1081 base = args[i-1].start + args[i-1].num;1082 for (j = i; j < thread_nr; j++) {1083 args[j].num = num_per_thread;1084 args[j].start = base + (j - i) * args[i].num;1085 }1086 1087 for (i = 0; i < thread_nr; i++) {1088 if (pthread_create(&synthesize_threads[i], NULL,1089 synthesize_threads_worker, &args[i]))1090 goto out_join;1091 }1092 err = 0;1093out_join:1094 for (i = 0; i < thread_nr; i++)1095 pthread_join(synthesize_threads[i], NULL);1096 free(args);1097free_threads:1098 free(synthesize_threads);1099free_dirent:1100 for (i = 0; i < n; i++)1101 zfree(&dirent[i]);1102 free(dirent);1103 1104 return err;1105}1106 1107int __weak perf_event__synthesize_extra_kmaps(const struct perf_tool *tool __maybe_unused,1108 perf_event__handler_t process __maybe_unused,1109 struct machine *machine __maybe_unused)1110{1111 return 0;1112}1113 1114static int __perf_event__synthesize_kernel_mmap(const struct perf_tool *tool,1115 perf_event__handler_t process,1116 struct machine *machine)1117{1118 union perf_event *event;1119 size_t size = symbol_conf.buildid_mmap2 ?1120 sizeof(event->mmap2) : sizeof(event->mmap);1121 struct map *map = machine__kernel_map(machine);1122 struct kmap *kmap;1123 int err;1124 1125 if (map == NULL)1126 return -1;1127 1128 kmap = map__kmap(map);1129 if (!kmap->ref_reloc_sym)1130 return -1;1131 1132 /*1133 * We should get this from /sys/kernel/sections/.text, but till that is1134 * available use this, and after it is use this as a fallback for older1135 * kernels.1136 */1137 event = zalloc(size + machine->id_hdr_size);1138 if (event == NULL) {1139 pr_debug("Not enough memory synthesizing mmap event "1140 "for kernel modules\n");1141 return -1;1142 }1143 1144 if (machine__is_host(machine)) {1145 /*1146 * kernel uses PERF_RECORD_MISC_USER for user space maps,1147 * see kernel/perf_event.c __perf_event_mmap1148 */1149 event->header.misc = PERF_RECORD_MISC_KERNEL;1150 } else {1151 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;1152 }1153 1154 if (symbol_conf.buildid_mmap2) {1155 size = snprintf(event->mmap2.filename, sizeof(event->mmap2.filename),1156 "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;1157 size = PERF_ALIGN(size, sizeof(u64));1158 event->mmap2.header.type = PERF_RECORD_MMAP2;1159 event->mmap2.header.size = (sizeof(event->mmap2) -1160 (sizeof(event->mmap2.filename) - size) + machine->id_hdr_size);1161 event->mmap2.pgoff = kmap->ref_reloc_sym->addr;1162 event->mmap2.start = map__start(map);1163 event->mmap2.len = map__end(map) - event->mmap.start;1164 event->mmap2.pid = machine->pid;1165 1166 perf_record_mmap2__read_build_id(&event->mmap2, machine, true);1167 } else {1168 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),1169 "%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;1170 size = PERF_ALIGN(size, sizeof(u64));1171 event->mmap.header.type = PERF_RECORD_MMAP;1172 event->mmap.header.size = (sizeof(event->mmap) -1173 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);1174 event->mmap.pgoff = kmap->ref_reloc_sym->addr;1175 event->mmap.start = map__start(map);1176 event->mmap.len = map__end(map) - event->mmap.start;1177 event->mmap.pid = machine->pid;1178 }1179 1180 err = perf_tool__process_synth_event(tool, event, machine, process);1181 free(event);1182 1183 return err;1184}1185 1186int perf_event__synthesize_kernel_mmap(const struct perf_tool *tool,1187 perf_event__handler_t process,1188 struct machine *machine)1189{1190 int err;1191 1192 err = __perf_event__synthesize_kernel_mmap(tool, process, machine);1193 if (err < 0)1194 return err;1195 1196 return perf_event__synthesize_extra_kmaps(tool, process, machine);1197}1198 1199int perf_event__synthesize_thread_map2(const struct perf_tool *tool,1200 struct perf_thread_map *threads,1201 perf_event__handler_t process,1202 struct machine *machine)1203{1204 union perf_event *event;1205 int i, err, size;1206 1207 size = sizeof(event->thread_map);1208 size += threads->nr * sizeof(event->thread_map.entries[0]);1209 1210 event = zalloc(size);1211 if (!event)1212 return -ENOMEM;1213 1214 event->header.type = PERF_RECORD_THREAD_MAP;1215 event->header.size = size;1216 event->thread_map.nr = threads->nr;1217 1218 for (i = 0; i < threads->nr; i++) {1219 struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i];1220 char *comm = perf_thread_map__comm(threads, i);1221 1222 if (!comm)1223 comm = (char *) "";1224 1225 entry->pid = perf_thread_map__pid(threads, i);1226 strncpy((char *) &entry->comm, comm, sizeof(entry->comm));1227 }1228 1229 err = process(tool, event, NULL, machine);1230 1231 free(event);1232 return err;1233}1234 1235struct synthesize_cpu_map_data {1236 const struct perf_cpu_map *map;1237 int nr;1238 int min_cpu;1239 int max_cpu;1240 int has_any_cpu;1241 int type;1242 size_t size;1243 struct perf_record_cpu_map_data *data;1244};1245 1246static void synthesize_cpus(struct synthesize_cpu_map_data *data)1247{1248 data->data->type = PERF_CPU_MAP__CPUS;1249 data->data->cpus_data.nr = data->nr;1250 for (int i = 0; i < data->nr; i++)1251 data->data->cpus_data.cpu[i] = perf_cpu_map__cpu(data->map, i).cpu;1252}1253 1254static void synthesize_mask(struct synthesize_cpu_map_data *data)1255{1256 int idx;1257 struct perf_cpu cpu;1258 1259 /* Due to padding, the 4bytes per entry mask variant is always smaller. */1260 data->data->type = PERF_CPU_MAP__MASK;1261 data->data->mask32_data.nr = BITS_TO_U32(data->max_cpu);1262 data->data->mask32_data.long_size = 4;1263 1264 perf_cpu_map__for_each_cpu(cpu, idx, data->map) {1265 int bit_word = cpu.cpu / 32;1266 u32 bit_mask = 1U << (cpu.cpu & 31);1267 1268 data->data->mask32_data.mask[bit_word] |= bit_mask;1269 }1270}1271 1272static void synthesize_range_cpus(struct synthesize_cpu_map_data *data)1273{1274 data->data->type = PERF_CPU_MAP__RANGE_CPUS;1275 data->data->range_cpu_data.any_cpu = data->has_any_cpu;1276 data->data->range_cpu_data.start_cpu = data->min_cpu;1277 data->data->range_cpu_data.end_cpu = data->max_cpu;1278}1279 1280static void *cpu_map_data__alloc(struct synthesize_cpu_map_data *syn_data,1281 size_t header_size)1282{1283 size_t size_cpus, size_mask;1284 1285 syn_data->nr = perf_cpu_map__nr(syn_data->map);1286 syn_data->has_any_cpu = (perf_cpu_map__cpu(syn_data->map, 0).cpu == -1) ? 1 : 0;1287 1288 syn_data->min_cpu = perf_cpu_map__cpu(syn_data->map, syn_data->has_any_cpu).cpu;1289 syn_data->max_cpu = perf_cpu_map__max(syn_data->map).cpu;1290 if (syn_data->max_cpu - syn_data->min_cpu + 1 == syn_data->nr - syn_data->has_any_cpu) {1291 /* A consecutive range of CPUs can be encoded using a range. */1292 assert(sizeof(u16) + sizeof(struct perf_record_range_cpu_map) == sizeof(u64));1293 syn_data->type = PERF_CPU_MAP__RANGE_CPUS;1294 syn_data->size = header_size + sizeof(u64);1295 return zalloc(syn_data->size);1296 }1297 1298 size_cpus = sizeof(u16) + sizeof(struct cpu_map_entries) + syn_data->nr * sizeof(u16);1299 /* Due to padding, the 4bytes per entry mask variant is always smaller. */1300 size_mask = sizeof(u16) + sizeof(struct perf_record_mask_cpu_map32) +1301 BITS_TO_U32(syn_data->max_cpu) * sizeof(__u32);1302 if (syn_data->has_any_cpu || size_cpus < size_mask) {1303 /* Follow the CPU map encoding. */1304 syn_data->type = PERF_CPU_MAP__CPUS;1305 syn_data->size = header_size + PERF_ALIGN(size_cpus, sizeof(u64));1306 return zalloc(syn_data->size);1307 }1308 /* Encode using a bitmask. */1309 syn_data->type = PERF_CPU_MAP__MASK;1310 syn_data->size = header_size + PERF_ALIGN(size_mask, sizeof(u64));1311 return zalloc(syn_data->size);1312}1313 1314static void cpu_map_data__synthesize(struct synthesize_cpu_map_data *data)1315{1316 switch (data->type) {1317 case PERF_CPU_MAP__CPUS:1318 synthesize_cpus(data);1319 break;1320 case PERF_CPU_MAP__MASK:1321 synthesize_mask(data);1322 break;1323 case PERF_CPU_MAP__RANGE_CPUS:1324 synthesize_range_cpus(data);1325 break;1326 default:1327 break;1328 }1329}1330 1331static struct perf_record_cpu_map *cpu_map_event__new(const struct perf_cpu_map *map)1332{1333 struct synthesize_cpu_map_data syn_data = { .map = map };1334 struct perf_record_cpu_map *event;1335 1336 1337 event = cpu_map_data__alloc(&syn_data, sizeof(struct perf_event_header));1338 if (!event)1339 return NULL;1340 1341 syn_data.data = &event->data;1342 event->header.type = PERF_RECORD_CPU_MAP;1343 event->header.size = syn_data.size;1344 cpu_map_data__synthesize(&syn_data);1345 return event;1346}1347 1348 1349int perf_event__synthesize_cpu_map(const struct perf_tool *tool,1350 const struct perf_cpu_map *map,1351 perf_event__handler_t process,1352 struct machine *machine)1353{1354 struct perf_record_cpu_map *event;1355 int err;1356 1357 event = cpu_map_event__new(map);1358 if (!event)1359 return -ENOMEM;1360 1361 err = process(tool, (union perf_event *) event, NULL, machine);1362 1363 free(event);1364 return err;1365}1366 1367int perf_event__synthesize_stat_config(const struct perf_tool *tool,1368 struct perf_stat_config *config,1369 perf_event__handler_t process,1370 struct machine *machine)1371{1372 struct perf_record_stat_config *event;1373 int size, i = 0, err;1374 1375 size = sizeof(*event);1376 size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));1377 1378 event = zalloc(size);1379 if (!event)1380 return -ENOMEM;1381 1382 event->header.type = PERF_RECORD_STAT_CONFIG;1383 event->header.size = size;1384 event->nr = PERF_STAT_CONFIG_TERM__MAX;1385 1386#define ADD(__term, __val) \1387 event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term; \1388 event->data[i].val = __val; \1389 i++;1390 1391 ADD(AGGR_MODE, config->aggr_mode)1392 ADD(INTERVAL, config->interval)1393 ADD(SCALE, config->scale)1394 ADD(AGGR_LEVEL, config->aggr_level)1395 1396 WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,1397 "stat config terms unbalanced\n");1398#undef ADD1399 1400 err = process(tool, (union perf_event *) event, NULL, machine);1401 1402 free(event);1403 return err;1404}1405 1406int perf_event__synthesize_stat(const struct perf_tool *tool,1407 struct perf_cpu cpu, u32 thread, u64 id,1408 struct perf_counts_values *count,1409 perf_event__handler_t process,1410 struct machine *machine)1411{1412 struct perf_record_stat event;1413 1414 event.header.type = PERF_RECORD_STAT;1415 event.header.size = sizeof(event);1416 event.header.misc = 0;1417 1418 event.id = id;1419 event.cpu = cpu.cpu;1420 event.thread = thread;1421 event.val = count->val;1422 event.ena = count->ena;1423 event.run = count->run;1424 1425 return process(tool, (union perf_event *) &event, NULL, machine);1426}1427 1428int perf_event__synthesize_stat_round(const struct perf_tool *tool,1429 u64 evtime, u64 type,1430 perf_event__handler_t process,1431 struct machine *machine)1432{1433 struct perf_record_stat_round event;1434 1435 event.header.type = PERF_RECORD_STAT_ROUND;1436 event.header.size = sizeof(event);1437 event.header.misc = 0;1438 1439 event.time = evtime;1440 event.type = type;1441 1442 return process(tool, (union perf_event *) &event, NULL, machine);1443}1444 1445size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format)1446{1447 size_t sz, result = sizeof(struct perf_record_sample);1448 1449 if (type & PERF_SAMPLE_IDENTIFIER)1450 result += sizeof(u64);1451 1452 if (type & PERF_SAMPLE_IP)1453 result += sizeof(u64);1454 1455 if (type & PERF_SAMPLE_TID)1456 result += sizeof(u64);1457 1458 if (type & PERF_SAMPLE_TIME)1459 result += sizeof(u64);1460 1461 if (type & PERF_SAMPLE_ADDR)1462 result += sizeof(u64);1463 1464 if (type & PERF_SAMPLE_ID)1465 result += sizeof(u64);1466 1467 if (type & PERF_SAMPLE_STREAM_ID)1468 result += sizeof(u64);1469 1470 if (type & PERF_SAMPLE_CPU)1471 result += sizeof(u64);1472 1473 if (type & PERF_SAMPLE_PERIOD)1474 result += sizeof(u64);1475 1476 if (type & PERF_SAMPLE_READ) {1477 result += sizeof(u64);1478 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)1479 result += sizeof(u64);1480 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)1481 result += sizeof(u64);1482 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */1483 if (read_format & PERF_FORMAT_GROUP) {1484 sz = sample_read_value_size(read_format);1485 result += sz * sample->read.group.nr;1486 } else {1487 result += sizeof(u64);1488 if (read_format & PERF_FORMAT_LOST)1489 result += sizeof(u64);1490 }1491 }1492 1493 if (type & PERF_SAMPLE_CALLCHAIN) {1494 sz = (sample->callchain->nr + 1) * sizeof(u64);1495 result += sz;1496 }1497 1498 if (type & PERF_SAMPLE_RAW) {1499 result += sizeof(u32);1500 result += sample->raw_size;1501 }1502 1503 if (type & PERF_SAMPLE_BRANCH_STACK) {1504 sz = sample->branch_stack->nr * sizeof(struct branch_entry);1505 /* nr, hw_idx */1506 sz += 2 * sizeof(u64);1507 result += sz;1508 }1509 1510 if (type & PERF_SAMPLE_REGS_USER) {1511 if (sample->user_regs.abi) {1512 result += sizeof(u64);1513 sz = hweight64(sample->user_regs.mask) * sizeof(u64);1514 result += sz;1515 } else {1516 result += sizeof(u64);1517 }1518 }1519 1520 if (type & PERF_SAMPLE_STACK_USER) {1521 sz = sample->user_stack.size;1522 result += sizeof(u64);1523 if (sz) {1524 result += sz;1525 result += sizeof(u64);1526 }1527 }1528 1529 if (type & PERF_SAMPLE_WEIGHT_TYPE)1530 result += sizeof(u64);1531 1532 if (type & PERF_SAMPLE_DATA_SRC)1533 result += sizeof(u64);1534 1535 if (type & PERF_SAMPLE_TRANSACTION)1536 result += sizeof(u64);1537 1538 if (type & PERF_SAMPLE_REGS_INTR) {1539 if (sample->intr_regs.abi) {1540 result += sizeof(u64);1541 sz = hweight64(sample->intr_regs.mask) * sizeof(u64);1542 result += sz;1543 } else {1544 result += sizeof(u64);1545 }1546 }1547 1548 if (type & PERF_SAMPLE_PHYS_ADDR)1549 result += sizeof(u64);1550 1551 if (type & PERF_SAMPLE_CGROUP)1552 result += sizeof(u64);1553 1554 if (type & PERF_SAMPLE_DATA_PAGE_SIZE)1555 result += sizeof(u64);1556 1557 if (type & PERF_SAMPLE_CODE_PAGE_SIZE)1558 result += sizeof(u64);1559 1560 if (type & PERF_SAMPLE_AUX) {1561 result += sizeof(u64);1562 result += sample->aux_sample.size;1563 }1564 1565 return result;1566}1567 1568void __weak arch_perf_synthesize_sample_weight(const struct perf_sample *data,1569 __u64 *array, u64 type __maybe_unused)1570{1571 *array = data->weight;1572}1573 1574static __u64 *copy_read_group_values(__u64 *array, __u64 read_format,1575 const struct perf_sample *sample)1576{1577 size_t sz = sample_read_value_size(read_format);1578 struct sample_read_value *v = sample->read.group.values;1579 1580 sample_read_group__for_each(v, sample->read.group.nr, read_format) {1581 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */1582 memcpy(array, v, sz);1583 array = (void *)array + sz;1584 }1585 return array;1586}1587 1588int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,1589 const struct perf_sample *sample)1590{1591 __u64 *array;1592 size_t sz;1593 /*1594 * used for cross-endian analysis. See git commit 65014ab31595 * for why this goofiness is needed.1596 */1597 union u64_swap u;1598 1599 array = event->sample.array;1600 1601 if (type & PERF_SAMPLE_IDENTIFIER) {1602 *array = sample->id;1603 array++;1604 }1605 1606 if (type & PERF_SAMPLE_IP) {1607 *array = sample->ip;1608 array++;1609 }1610 1611 if (type & PERF_SAMPLE_TID) {1612 u.val32[0] = sample->pid;1613 u.val32[1] = sample->tid;1614 *array = u.val64;1615 array++;1616 }1617 1618 if (type & PERF_SAMPLE_TIME) {1619 *array = sample->time;1620 array++;1621 }1622 1623 if (type & PERF_SAMPLE_ADDR) {1624 *array = sample->addr;1625 array++;1626 }1627 1628 if (type & PERF_SAMPLE_ID) {1629 *array = sample->id;1630 array++;1631 }1632 1633 if (type & PERF_SAMPLE_STREAM_ID) {1634 *array = sample->stream_id;1635 array++;1636 }1637 1638 if (type & PERF_SAMPLE_CPU) {1639 u.val32[0] = sample->cpu;1640 u.val32[1] = 0;1641 *array = u.val64;1642 array++;1643 }1644 1645 if (type & PERF_SAMPLE_PERIOD) {1646 *array = sample->period;1647 array++;1648 }1649 1650 if (type & PERF_SAMPLE_READ) {1651 if (read_format & PERF_FORMAT_GROUP)1652 *array = sample->read.group.nr;1653 else1654 *array = sample->read.one.value;1655 array++;1656 1657 if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {1658 *array = sample->read.time_enabled;1659 array++;1660 }1661 1662 if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {1663 *array = sample->read.time_running;1664 array++;1665 }1666 1667 /* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */1668 if (read_format & PERF_FORMAT_GROUP) {1669 array = copy_read_group_values(array, read_format,1670 sample);1671 } else {1672 *array = sample->read.one.id;1673 array++;1674 1675 if (read_format & PERF_FORMAT_LOST) {1676 *array = sample->read.one.lost;1677 array++;1678 }1679 }1680 }1681 1682 if (type & PERF_SAMPLE_CALLCHAIN) {1683 sz = (sample->callchain->nr + 1) * sizeof(u64);1684 memcpy(array, sample->callchain, sz);1685 array = (void *)array + sz;1686 }1687 1688 if (type & PERF_SAMPLE_RAW) {1689 u.val32[0] = sample->raw_size;1690 *array = u.val64;1691 array = (void *)array + sizeof(u32);1692 1693 memcpy(array, sample->raw_data, sample->raw_size);1694 array = (void *)array + sample->raw_size;1695 }1696 1697 if (type & PERF_SAMPLE_BRANCH_STACK) {1698 sz = sample->branch_stack->nr * sizeof(struct branch_entry);1699 /* nr, hw_idx */1700 sz += 2 * sizeof(u64);1701 memcpy(array, sample->branch_stack, sz);1702 array = (void *)array + sz;1703 }1704 1705 if (type & PERF_SAMPLE_REGS_USER) {1706 if (sample->user_regs.abi) {1707 *array++ = sample->user_regs.abi;1708 sz = hweight64(sample->user_regs.mask) * sizeof(u64);1709 memcpy(array, sample->user_regs.regs, sz);1710 array = (void *)array + sz;1711 } else {1712 *array++ = 0;1713 }1714 }1715 1716 if (type & PERF_SAMPLE_STACK_USER) {1717 sz = sample->user_stack.size;1718 *array++ = sz;1719 if (sz) {1720 memcpy(array, sample->user_stack.data, sz);1721 array = (void *)array + sz;1722 *array++ = sz;1723 }1724 }1725 1726 if (type & PERF_SAMPLE_WEIGHT_TYPE) {1727 arch_perf_synthesize_sample_weight(sample, array, type);1728 array++;1729 }1730 1731 if (type & PERF_SAMPLE_DATA_SRC) {1732 *array = sample->data_src;1733 array++;1734 }1735 1736 if (type & PERF_SAMPLE_TRANSACTION) {1737 *array = sample->transaction;1738 array++;1739 }1740 1741 if (type & PERF_SAMPLE_REGS_INTR) {1742 if (sample->intr_regs.abi) {1743 *array++ = sample->intr_regs.abi;1744 sz = hweight64(sample->intr_regs.mask) * sizeof(u64);1745 memcpy(array, sample->intr_regs.regs, sz);1746 array = (void *)array + sz;1747 } else {1748 *array++ = 0;1749 }1750 }1751 1752 if (type & PERF_SAMPLE_PHYS_ADDR) {1753 *array = sample->phys_addr;1754 array++;1755 }1756 1757 if (type & PERF_SAMPLE_CGROUP) {1758 *array = sample->cgroup;1759 array++;1760 }1761 1762 if (type & PERF_SAMPLE_DATA_PAGE_SIZE) {1763 *array = sample->data_page_size;1764 array++;1765 }1766 1767 if (type & PERF_SAMPLE_CODE_PAGE_SIZE) {1768 *array = sample->code_page_size;1769 array++;1770 }1771 1772 if (type & PERF_SAMPLE_AUX) {1773 sz = sample->aux_sample.size;1774 *array++ = sz;1775 memcpy(array, sample->aux_sample.data, sz);1776 array = (void *)array + sz;1777 }1778 1779 return 0;1780}1781 1782int perf_event__synthesize_id_sample(__u64 *array, u64 type, const struct perf_sample *sample)1783{1784 __u64 *start = array;1785 1786 /*1787 * used for cross-endian analysis. See git commit 65014ab31788 * for why this goofiness is needed.1789 */1790 union u64_swap u;1791 1792 if (type & PERF_SAMPLE_TID) {1793 u.val32[0] = sample->pid;1794 u.val32[1] = sample->tid;1795 *array = u.val64;1796 array++;1797 }1798 1799 if (type & PERF_SAMPLE_TIME) {1800 *array = sample->time;1801 array++;1802 }1803 1804 if (type & PERF_SAMPLE_ID) {1805 *array = sample->id;1806 array++;1807 }1808 1809 if (type & PERF_SAMPLE_STREAM_ID) {1810 *array = sample->stream_id;1811 array++;1812 }1813 1814 if (type & PERF_SAMPLE_CPU) {1815 u.val32[0] = sample->cpu;1816 u.val32[1] = 0;1817 *array = u.val64;1818 array++;1819 }1820 1821 if (type & PERF_SAMPLE_IDENTIFIER) {1822 *array = sample->id;1823 array++;1824 }1825 1826 return (void *)array - (void *)start;1827}1828 1829int __perf_event__synthesize_id_index(const struct perf_tool *tool, perf_event__handler_t process,1830 struct evlist *evlist, struct machine *machine, size_t from)1831{1832 union perf_event *ev;1833 struct evsel *evsel;1834 size_t nr = 0, i = 0, sz, max_nr, n, pos;1835 size_t e1_sz = sizeof(struct id_index_entry);1836 size_t e2_sz = sizeof(struct id_index_entry_2);1837 size_t etot_sz = e1_sz + e2_sz;1838 bool e2_needed = false;1839 int err;1840 1841 max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) / etot_sz;1842 1843 pos = 0;1844 evlist__for_each_entry(evlist, evsel) {1845 if (pos++ < from)1846 continue;1847 nr += evsel->core.ids;1848 }1849 1850 if (!nr)1851 return 0;1852 1853 pr_debug2("Synthesizing id index\n");1854 1855 n = nr > max_nr ? max_nr : nr;1856 sz = sizeof(struct perf_record_id_index) + n * etot_sz;1857 ev = zalloc(sz);1858 if (!ev)1859 return -ENOMEM;1860 1861 sz = sizeof(struct perf_record_id_index) + n * e1_sz;1862 1863 ev->id_index.header.type = PERF_RECORD_ID_INDEX;1864 ev->id_index.nr = n;1865 1866 pos = 0;1867 evlist__for_each_entry(evlist, evsel) {1868 u32 j;1869 1870 if (pos++ < from)1871 continue;1872 for (j = 0; j < evsel->core.ids; j++, i++) {1873 struct id_index_entry *e;1874 struct id_index_entry_2 *e2;1875 struct perf_sample_id *sid;1876 1877 if (i >= n) {1878 ev->id_index.header.size = sz + (e2_needed ? n * e2_sz : 0);1879 err = process(tool, ev, NULL, machine);1880 if (err)1881 goto out_err;1882 nr -= n;1883 i = 0;1884 e2_needed = false;1885 }1886 1887 e = &ev->id_index.entries[i];1888 1889 e->id = evsel->core.id[j];1890 1891 sid = evlist__id2sid(evlist, e->id);1892 if (!sid) {1893 free(ev);1894 return -ENOENT;1895 }1896 1897 e->idx = sid->idx;1898 e->cpu = sid->cpu.cpu;1899 e->tid = sid->tid;1900 1901 if (sid->machine_pid)1902 e2_needed = true;1903 1904 e2 = (void *)ev + sz;1905 e2[i].machine_pid = sid->machine_pid;1906 e2[i].vcpu = sid->vcpu.cpu;1907 }1908 }1909 1910 sz = sizeof(struct perf_record_id_index) + nr * e1_sz;1911 ev->id_index.header.size = sz + (e2_needed ? nr * e2_sz : 0);1912 ev->id_index.nr = nr;1913 1914 err = process(tool, ev, NULL, machine);1915out_err:1916 free(ev);1917 1918 return err;1919}1920 1921int perf_event__synthesize_id_index(const struct perf_tool *tool, perf_event__handler_t process,1922 struct evlist *evlist, struct machine *machine)1923{1924 return __perf_event__synthesize_id_index(tool, process, evlist, machine, 0);1925}1926 1927int __machine__synthesize_threads(struct machine *machine, const struct perf_tool *tool,1928 struct target *target, struct perf_thread_map *threads,1929 perf_event__handler_t process, bool needs_mmap,1930 bool data_mmap, unsigned int nr_threads_synthesize)1931{1932 /*1933 * When perf runs in non-root PID namespace, and the namespace's proc FS1934 * is not mounted, nsinfo__is_in_root_namespace() returns false.1935 * In this case, the proc FS is coming for the parent namespace, thus1936 * perf tool will wrongly gather process info from its parent PID1937 * namespace.1938 *1939 * To avoid the confusion that the perf tool runs in a child PID1940 * namespace but it synthesizes thread info from its parent PID1941 * namespace, returns failure with warning.1942 */1943 if (!nsinfo__is_in_root_namespace()) {1944 pr_err("Perf runs in non-root PID namespace but it tries to ");1945 pr_err("gather process info from its parent PID namespace.\n");1946 pr_err("Please mount the proc file system properly, e.g. ");1947 pr_err("add the option '--mount-proc' for unshare command.\n");1948 return -EPERM;1949 }1950 1951 if (target__has_task(target))1952 return perf_event__synthesize_thread_map(tool, threads, process, machine,1953 needs_mmap, data_mmap);1954 else if (target__has_cpu(target))1955 return perf_event__synthesize_threads(tool, process, machine,1956 needs_mmap, data_mmap,1957 nr_threads_synthesize);1958 /* command specified */1959 return 0;1960}1961 1962int machine__synthesize_threads(struct machine *machine, struct target *target,1963 struct perf_thread_map *threads, bool needs_mmap,1964 bool data_mmap, unsigned int nr_threads_synthesize)1965{1966 return __machine__synthesize_threads(machine, NULL, target, threads,1967 perf_event__process, needs_mmap,1968 data_mmap, nr_threads_synthesize);1969}1970 1971static struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id)1972{1973 struct perf_record_event_update *ev;1974 1975 size += sizeof(*ev);1976 size = PERF_ALIGN(size, sizeof(u64));1977 1978 ev = zalloc(size);1979 if (ev) {1980 ev->header.type = PERF_RECORD_EVENT_UPDATE;1981 ev->header.size = (u16)size;1982 ev->type = type;1983 ev->id = id;1984 }1985 return ev;1986}1987 1988int perf_event__synthesize_event_update_unit(const struct perf_tool *tool, struct evsel *evsel,1989 perf_event__handler_t process)1990{1991 size_t size = strlen(evsel->unit);1992 struct perf_record_event_update *ev;1993 int err;1994 1995 ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]);1996 if (ev == NULL)1997 return -ENOMEM;1998 1999 strlcpy(ev->unit, evsel->unit, size + 1);2000 err = process(tool, (union perf_event *)ev, NULL, NULL);2001 free(ev);2002 return err;2003}2004 2005int perf_event__synthesize_event_update_scale(const struct perf_tool *tool, struct evsel *evsel,2006 perf_event__handler_t process)2007{2008 struct perf_record_event_update *ev;2009 struct perf_record_event_update_scale *ev_data;2010 int err;2011 2012 ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]);2013 if (ev == NULL)2014 return -ENOMEM;2015 2016 ev->scale.scale = evsel->scale;2017 err = process(tool, (union perf_event *)ev, NULL, NULL);2018 free(ev);2019 return err;2020}2021 2022int perf_event__synthesize_event_update_name(const struct perf_tool *tool, struct evsel *evsel,2023 perf_event__handler_t process)2024{2025 struct perf_record_event_update *ev;2026 size_t len = strlen(evsel__name(evsel));2027 int err;2028 2029 ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]);2030 if (ev == NULL)2031 return -ENOMEM;2032 2033 strlcpy(ev->name, evsel->name, len + 1);2034 err = process(tool, (union perf_event *)ev, NULL, NULL);2035 free(ev);2036 return err;2037}2038 2039int perf_event__synthesize_event_update_cpus(const struct perf_tool *tool, struct evsel *evsel,2040 perf_event__handler_t process)2041{2042 struct synthesize_cpu_map_data syn_data = { .map = evsel->core.own_cpus };2043 struct perf_record_event_update *ev;2044 int err;2045 2046 ev = cpu_map_data__alloc(&syn_data, sizeof(struct perf_event_header) + 2 * sizeof(u64));2047 if (!ev)2048 return -ENOMEM;2049 2050 syn_data.data = &ev->cpus.cpus;2051 ev->header.type = PERF_RECORD_EVENT_UPDATE;2052 ev->header.size = (u16)syn_data.size;2053 ev->type = PERF_EVENT_UPDATE__CPUS;2054 ev->id = evsel->core.id[0];2055 cpu_map_data__synthesize(&syn_data);2056 2057 err = process(tool, (union perf_event *)ev, NULL, NULL);2058 free(ev);2059 return err;2060}2061 2062int perf_event__synthesize_attrs(const struct perf_tool *tool, struct evlist *evlist,2063 perf_event__handler_t process)2064{2065 struct evsel *evsel;2066 int err = 0;2067 2068 evlist__for_each_entry(evlist, evsel) {2069 err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids,2070 evsel->core.id, process);2071 if (err) {2072 pr_debug("failed to create perf header attribute\n");2073 return err;2074 }2075 }2076 2077 return err;2078}2079 2080static bool has_unit(struct evsel *evsel)2081{2082 return evsel->unit && *evsel->unit;2083}2084 2085static bool has_scale(struct evsel *evsel)2086{2087 return evsel->scale != 1;2088}2089 2090int perf_event__synthesize_extra_attr(const struct perf_tool *tool, struct evlist *evsel_list,2091 perf_event__handler_t process, bool is_pipe)2092{2093 struct evsel *evsel;2094 int err;2095 2096 /*2097 * Synthesize other events stuff not carried within2098 * attr event - unit, scale, name2099 */2100 evlist__for_each_entry(evsel_list, evsel) {2101 if (!evsel->supported)2102 continue;2103 2104 /*2105 * Synthesize unit and scale only if it's defined.2106 */2107 if (has_unit(evsel)) {2108 err = perf_event__synthesize_event_update_unit(tool, evsel, process);2109 if (err < 0) {2110 pr_err("Couldn't synthesize evsel unit.\n");2111 return err;2112 }2113 }2114 2115 if (has_scale(evsel)) {2116 err = perf_event__synthesize_event_update_scale(tool, evsel, process);2117 if (err < 0) {2118 pr_err("Couldn't synthesize evsel evsel.\n");2119 return err;2120 }2121 }2122 2123 if (evsel->core.own_cpus) {2124 err = perf_event__synthesize_event_update_cpus(tool, evsel, process);2125 if (err < 0) {2126 pr_err("Couldn't synthesize evsel cpus.\n");2127 return err;2128 }2129 }2130 2131 /*2132 * Name is needed only for pipe output,2133 * perf.data carries event names.2134 */2135 if (is_pipe) {2136 err = perf_event__synthesize_event_update_name(tool, evsel, process);2137 if (err < 0) {2138 pr_err("Couldn't synthesize evsel name.\n");2139 return err;2140 }2141 }2142 }2143 return 0;2144}2145 2146int perf_event__synthesize_attr(const struct perf_tool *tool, struct perf_event_attr *attr,2147 u32 ids, u64 *id, perf_event__handler_t process)2148{2149 union perf_event *ev;2150 size_t size;2151 int err;2152 2153 size = sizeof(struct perf_event_attr);2154 size = PERF_ALIGN(size, sizeof(u64));2155 size += sizeof(struct perf_event_header);2156 size += ids * sizeof(u64);2157 2158 ev = zalloc(size);2159 2160 if (ev == NULL)2161 return -ENOMEM;2162 2163 ev->attr.attr = *attr;2164 memcpy(perf_record_header_attr_id(ev), id, ids * sizeof(u64));2165 2166 ev->attr.header.type = PERF_RECORD_HEADER_ATTR;2167 ev->attr.header.size = (u16)size;2168 2169 if (ev->attr.header.size == size)2170 err = process(tool, ev, NULL, NULL);2171 else2172 err = -E2BIG;2173 2174 free(ev);2175 2176 return err;2177}2178 2179#ifdef HAVE_LIBTRACEEVENT2180int perf_event__synthesize_tracing_data(const struct perf_tool *tool, int fd, struct evlist *evlist,2181 perf_event__handler_t process)2182{2183 union perf_event ev;2184 struct tracing_data *tdata;2185 ssize_t size = 0, aligned_size = 0, padding;2186 struct feat_fd ff;2187 2188 /*2189 * We are going to store the size of the data followed2190 * by the data contents. Since the fd descriptor is a pipe,2191 * we cannot seek back to store the size of the data once2192 * we know it. Instead we:2193 *2194 * - write the tracing data to the temp file2195 * - get/write the data size to pipe2196 * - write the tracing data from the temp file2197 * to the pipe2198 */2199 tdata = tracing_data_get(&evlist->core.entries, fd, true);2200 if (!tdata)2201 return -1;2202 2203 memset(&ev, 0, sizeof(ev.tracing_data));2204 2205 ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;2206 size = tdata->size;2207 aligned_size = PERF_ALIGN(size, sizeof(u64));2208 padding = aligned_size - size;2209 ev.tracing_data.header.size = sizeof(ev.tracing_data);2210 ev.tracing_data.size = aligned_size;2211 2212 process(tool, &ev, NULL, NULL);2213 2214 /*2215 * The put function will copy all the tracing data2216 * stored in temp file to the pipe.2217 */2218 tracing_data_put(tdata);2219 2220 ff = (struct feat_fd){ .fd = fd };2221 if (write_padded(&ff, NULL, 0, padding))2222 return -1;2223 2224 return aligned_size;2225}2226#endif2227 2228int perf_event__synthesize_build_id(const struct perf_tool *tool,2229 struct perf_sample *sample,2230 struct machine *machine,2231 perf_event__handler_t process,2232 const struct evsel *evsel,2233 __u16 misc,2234 const struct build_id *bid,2235 const char *filename)2236{2237 union perf_event ev;2238 size_t len;2239 2240 len = sizeof(ev.build_id) + strlen(filename) + 1;2241 len = PERF_ALIGN(len, sizeof(u64));2242 2243 memset(&ev, 0, len);2244 2245 ev.build_id.size = min(bid->size, sizeof(ev.build_id.build_id));2246 memcpy(ev.build_id.build_id, bid->data, ev.build_id.size);2247 ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;2248 ev.build_id.header.misc = misc | PERF_RECORD_MISC_BUILD_ID_SIZE;2249 ev.build_id.pid = machine->pid;2250 ev.build_id.header.size = len;2251 strcpy(ev.build_id.filename, filename);2252 2253 if (evsel) {2254 void *array = &ev;2255 int ret;2256 2257 array += ev.header.size;2258 ret = perf_event__synthesize_id_sample(array, evsel->core.attr.sample_type, sample);2259 if (ret < 0)2260 return ret;2261 2262 if (ret & 7) {2263 pr_err("Bad id sample size %d\n", ret);2264 return -EINVAL;2265 }2266 2267 ev.header.size += ret;2268 }2269 2270 return process(tool, &ev, sample, machine);2271}2272 2273int perf_event__synthesize_mmap2_build_id(const struct perf_tool *tool,2274 struct perf_sample *sample,2275 struct machine *machine,2276 perf_event__handler_t process,2277 const struct evsel *evsel,2278 __u16 misc,2279 __u32 pid, __u32 tid,2280 __u64 start, __u64 len, __u64 pgoff,2281 const struct build_id *bid,2282 __u32 prot, __u32 flags,2283 const char *filename)2284{2285 union perf_event ev;2286 size_t ev_len;2287 void *array;2288 int ret;2289 2290 ev_len = sizeof(ev.mmap2) - sizeof(ev.mmap2.filename) + strlen(filename) + 1;2291 ev_len = PERF_ALIGN(ev_len, sizeof(u64));2292 2293 memset(&ev, 0, ev_len);2294 2295 ev.mmap2.header.type = PERF_RECORD_MMAP2;2296 ev.mmap2.header.misc = misc | PERF_RECORD_MISC_MMAP_BUILD_ID;2297 ev.mmap2.header.size = ev_len;2298 2299 ev.mmap2.pid = pid;2300 ev.mmap2.tid = tid;2301 ev.mmap2.start = start;2302 ev.mmap2.len = len;2303 ev.mmap2.pgoff = pgoff;2304 2305 ev.mmap2.build_id_size = min(bid->size, sizeof(ev.mmap2.build_id));2306 memcpy(ev.mmap2.build_id, bid->data, ev.mmap2.build_id_size);2307 2308 ev.mmap2.prot = prot;2309 ev.mmap2.flags = flags;2310 2311 memcpy(ev.mmap2.filename, filename, min(strlen(filename), sizeof(ev.mmap.filename)));2312 2313 array = &ev;2314 array += ev.header.size;2315 ret = perf_event__synthesize_id_sample(array, evsel->core.attr.sample_type, sample);2316 if (ret < 0)2317 return ret;2318 2319 if (ret & 7) {2320 pr_err("Bad id sample size %d\n", ret);2321 return -EINVAL;2322 }2323 2324 ev.header.size += ret;2325 2326 return process(tool, &ev, sample, machine);2327}2328 2329int perf_event__synthesize_stat_events(struct perf_stat_config *config, const struct perf_tool *tool,2330 struct evlist *evlist, perf_event__handler_t process, bool attrs)2331{2332 int err;2333 2334 if (attrs) {2335 err = perf_event__synthesize_attrs(tool, evlist, process);2336 if (err < 0) {2337 pr_err("Couldn't synthesize attrs.\n");2338 return err;2339 }2340 }2341 2342 err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs);2343 err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL);2344 if (err < 0) {2345 pr_err("Couldn't synthesize thread map.\n");2346 return err;2347 }2348 2349 err = perf_event__synthesize_cpu_map(tool, evlist->core.user_requested_cpus, process, NULL);2350 if (err < 0) {2351 pr_err("Couldn't synthesize thread map.\n");2352 return err;2353 }2354 2355 err = perf_event__synthesize_stat_config(tool, config, process, NULL);2356 if (err < 0) {2357 pr_err("Couldn't synthesize config.\n");2358 return err;2359 }2360 2361 return 0;2362}2363 2364extern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE];2365 2366int perf_event__synthesize_features(const struct perf_tool *tool, struct perf_session *session,2367 struct evlist *evlist, perf_event__handler_t process)2368{2369 struct perf_header *header = &session->header;2370 struct perf_record_header_feature *fe;2371 struct feat_fd ff;2372 size_t sz, sz_hdr;2373 int feat, ret;2374 2375 sz_hdr = sizeof(fe->header);2376 sz = sizeof(union perf_event);2377 /* get a nice alignment */2378 sz = PERF_ALIGN(sz, page_size);2379 2380 memset(&ff, 0, sizeof(ff));2381 2382 ff.buf = malloc(sz);2383 if (!ff.buf)2384 return -ENOMEM;2385 2386 ff.size = sz - sz_hdr;2387 ff.ph = &session->header;2388 2389 for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {2390 if (!feat_ops[feat].synthesize) {2391 pr_debug("No record header feature for header :%d\n", feat);2392 continue;2393 }2394 2395 ff.offset = sizeof(*fe);2396 2397 ret = feat_ops[feat].write(&ff, evlist);2398 if (ret || ff.offset <= (ssize_t)sizeof(*fe)) {2399 pr_debug("Error writing feature\n");2400 continue;2401 }2402 /* ff.buf may have changed due to realloc in do_write() */2403 fe = ff.buf;2404 memset(fe, 0, sizeof(*fe));2405 2406 fe->feat_id = feat;2407 fe->header.type = PERF_RECORD_HEADER_FEATURE;2408 fe->header.size = ff.offset;2409 2410 ret = process(tool, ff.buf, NULL, NULL);2411 if (ret) {2412 free(ff.buf);2413 return ret;2414 }2415 }2416 2417 /* Send HEADER_LAST_FEATURE mark. */2418 fe = ff.buf;2419 fe->feat_id = HEADER_LAST_FEATURE;2420 fe->header.type = PERF_RECORD_HEADER_FEATURE;2421 fe->header.size = sizeof(*fe);2422 2423 ret = process(tool, ff.buf, NULL, NULL);2424 2425 free(ff.buf);2426 return ret;2427}2428 2429int perf_event__synthesize_for_pipe(const struct perf_tool *tool,2430 struct perf_session *session,2431 struct perf_data *data,2432 perf_event__handler_t process)2433{2434 int err;2435 int ret = 0;2436 struct evlist *evlist = session->evlist;2437 2438 /*2439 * We need to synthesize events first, because some2440 * features works on top of them (on report side).2441 */2442 err = perf_event__synthesize_attrs(tool, evlist, process);2443 if (err < 0) {2444 pr_err("Couldn't synthesize attrs.\n");2445 return err;2446 }2447 ret += err;2448 2449 err = perf_event__synthesize_features(tool, session, evlist, process);2450 if (err < 0) {2451 pr_err("Couldn't synthesize features.\n");2452 return err;2453 }2454 ret += err;2455 2456#ifdef HAVE_LIBTRACEEVENT2457 if (have_tracepoints(&evlist->core.entries)) {2458 int fd = perf_data__fd(data);2459 2460 /*2461 * FIXME err <= 0 here actually means that2462 * there were no tracepoints so its not really2463 * an error, just that we don't need to2464 * synthesize anything. We really have to2465 * return this more properly and also2466 * propagate errors that now are calling die()2467 */2468 err = perf_event__synthesize_tracing_data(tool, fd, evlist,2469 process);2470 if (err <= 0) {2471 pr_err("Couldn't record tracing data.\n");2472 return err;2473 }2474 ret += err;2475 }2476#else2477 (void)data;2478#endif2479 2480 return ret;2481}2482 2483int parse_synth_opt(char *synth)2484{2485 char *p, *q;2486 int ret = 0;2487 2488 if (synth == NULL)2489 return -1;2490 2491 for (q = synth; (p = strsep(&q, ",")); p = q) {2492 if (!strcasecmp(p, "no") || !strcasecmp(p, "none"))2493 return 0;2494 2495 if (!strcasecmp(p, "all"))2496 return PERF_SYNTH_ALL;2497 2498 if (!strcasecmp(p, "task"))2499 ret |= PERF_SYNTH_TASK;2500 else if (!strcasecmp(p, "mmap"))2501 ret |= PERF_SYNTH_TASK | PERF_SYNTH_MMAP;2502 else if (!strcasecmp(p, "cgroup"))2503 ret |= PERF_SYNTH_CGROUP;2504 else2505 return -1;2506 }2507 2508 return ret;2509}2510