18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci
38c2ecf20Sopenharmony_ci#include "util/debug.h"
48c2ecf20Sopenharmony_ci#include "util/dso.h"
58c2ecf20Sopenharmony_ci#include "util/event.h"
68c2ecf20Sopenharmony_ci#include "util/evlist.h"
78c2ecf20Sopenharmony_ci#include "util/machine.h"
88c2ecf20Sopenharmony_ci#include "util/map.h"
98c2ecf20Sopenharmony_ci#include "util/map_symbol.h"
108c2ecf20Sopenharmony_ci#include "util/branch.h"
118c2ecf20Sopenharmony_ci#include "util/memswap.h"
128c2ecf20Sopenharmony_ci#include "util/namespaces.h"
138c2ecf20Sopenharmony_ci#include "util/session.h"
148c2ecf20Sopenharmony_ci#include "util/stat.h"
158c2ecf20Sopenharmony_ci#include "util/symbol.h"
168c2ecf20Sopenharmony_ci#include "util/synthetic-events.h"
178c2ecf20Sopenharmony_ci#include "util/target.h"
188c2ecf20Sopenharmony_ci#include "util/time-utils.h"
198c2ecf20Sopenharmony_ci#include "util/cgroup.h"
208c2ecf20Sopenharmony_ci#include <linux/bitops.h>
218c2ecf20Sopenharmony_ci#include <linux/kernel.h>
228c2ecf20Sopenharmony_ci#include <linux/string.h>
238c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
248c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
258c2ecf20Sopenharmony_ci#include <asm/bug.h>
268c2ecf20Sopenharmony_ci#include <perf/evsel.h>
278c2ecf20Sopenharmony_ci#include <internal/cpumap.h>
288c2ecf20Sopenharmony_ci#include <perf/cpumap.h>
298c2ecf20Sopenharmony_ci#include <internal/lib.h> // page_size
308c2ecf20Sopenharmony_ci#include <internal/threadmap.h>
318c2ecf20Sopenharmony_ci#include <perf/threadmap.h>
328c2ecf20Sopenharmony_ci#include <symbol/kallsyms.h>
338c2ecf20Sopenharmony_ci#include <dirent.h>
348c2ecf20Sopenharmony_ci#include <errno.h>
358c2ecf20Sopenharmony_ci#include <inttypes.h>
368c2ecf20Sopenharmony_ci#include <stdio.h>
378c2ecf20Sopenharmony_ci#include <string.h>
388c2ecf20Sopenharmony_ci#include <uapi/linux/mman.h> /* To get things like MAP_HUGETLB even on older libc headers */
398c2ecf20Sopenharmony_ci#include <api/fs/fs.h>
408c2ecf20Sopenharmony_ci#include <api/io.h>
418c2ecf20Sopenharmony_ci#include <sys/types.h>
428c2ecf20Sopenharmony_ci#include <sys/stat.h>
438c2ecf20Sopenharmony_ci#include <fcntl.h>
448c2ecf20Sopenharmony_ci#include <unistd.h>
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci#define DEFAULT_PROC_MAP_PARSE_TIMEOUT 500
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciunsigned int proc_map_timeout = DEFAULT_PROC_MAP_PARSE_TIMEOUT;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciint perf_tool__process_synth_event(struct perf_tool *tool,
518c2ecf20Sopenharmony_ci				   union perf_event *event,
528c2ecf20Sopenharmony_ci				   struct machine *machine,
538c2ecf20Sopenharmony_ci				   perf_event__handler_t process)
548c2ecf20Sopenharmony_ci{
558c2ecf20Sopenharmony_ci	struct perf_sample synth_sample = {
568c2ecf20Sopenharmony_ci		.pid	   = -1,
578c2ecf20Sopenharmony_ci		.tid	   = -1,
588c2ecf20Sopenharmony_ci		.time	   = -1,
598c2ecf20Sopenharmony_ci		.stream_id = -1,
608c2ecf20Sopenharmony_ci		.cpu	   = -1,
618c2ecf20Sopenharmony_ci		.period	   = 1,
628c2ecf20Sopenharmony_ci		.cpumode   = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK,
638c2ecf20Sopenharmony_ci	};
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	return process(tool, event, &synth_sample, machine);
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*
698c2ecf20Sopenharmony_ci * Assumes that the first 4095 bytes of /proc/pid/stat contains
708c2ecf20Sopenharmony_ci * the comm, tgid and ppid.
718c2ecf20Sopenharmony_ci */
728c2ecf20Sopenharmony_cistatic int perf_event__get_comm_ids(pid_t pid, char *comm, size_t len,
738c2ecf20Sopenharmony_ci				    pid_t *tgid, pid_t *ppid)
748c2ecf20Sopenharmony_ci{
758c2ecf20Sopenharmony_ci	char bf[4096];
768c2ecf20Sopenharmony_ci	int fd;
778c2ecf20Sopenharmony_ci	size_t size = 0;
788c2ecf20Sopenharmony_ci	ssize_t n;
798c2ecf20Sopenharmony_ci	char *name, *tgids, *ppids;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	*tgid = -1;
828c2ecf20Sopenharmony_ci	*ppid = -1;
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_ci	snprintf(bf, sizeof(bf), "/proc/%d/status", pid);
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	fd = open(bf, O_RDONLY);
878c2ecf20Sopenharmony_ci	if (fd < 0) {
888c2ecf20Sopenharmony_ci		pr_debug("couldn't open %s\n", bf);
898c2ecf20Sopenharmony_ci		return -1;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	n = read(fd, bf, sizeof(bf) - 1);
938c2ecf20Sopenharmony_ci	close(fd);
948c2ecf20Sopenharmony_ci	if (n <= 0) {
958c2ecf20Sopenharmony_ci		pr_warning("Couldn't get COMM, tigd and ppid for pid %d\n",
968c2ecf20Sopenharmony_ci			   pid);
978c2ecf20Sopenharmony_ci		return -1;
988c2ecf20Sopenharmony_ci	}
998c2ecf20Sopenharmony_ci	bf[n] = '\0';
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	name = strstr(bf, "Name:");
1028c2ecf20Sopenharmony_ci	tgids = strstr(bf, "Tgid:");
1038c2ecf20Sopenharmony_ci	ppids = strstr(bf, "PPid:");
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (name) {
1068c2ecf20Sopenharmony_ci		char *nl;
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci		name = skip_spaces(name + 5);  /* strlen("Name:") */
1098c2ecf20Sopenharmony_ci		nl = strchr(name, '\n');
1108c2ecf20Sopenharmony_ci		if (nl)
1118c2ecf20Sopenharmony_ci			*nl = '\0';
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		size = strlen(name);
1148c2ecf20Sopenharmony_ci		if (size >= len)
1158c2ecf20Sopenharmony_ci			size = len - 1;
1168c2ecf20Sopenharmony_ci		memcpy(comm, name, size);
1178c2ecf20Sopenharmony_ci		comm[size] = '\0';
1188c2ecf20Sopenharmony_ci	} else {
1198c2ecf20Sopenharmony_ci		pr_debug("Name: string not found for pid %d\n", pid);
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	if (tgids) {
1238c2ecf20Sopenharmony_ci		tgids += 5;  /* strlen("Tgid:") */
1248c2ecf20Sopenharmony_ci		*tgid = atoi(tgids);
1258c2ecf20Sopenharmony_ci	} else {
1268c2ecf20Sopenharmony_ci		pr_debug("Tgid: string not found for pid %d\n", pid);
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	if (ppids) {
1308c2ecf20Sopenharmony_ci		ppids += 5;  /* strlen("PPid:") */
1318c2ecf20Sopenharmony_ci		*ppid = atoi(ppids);
1328c2ecf20Sopenharmony_ci	} else {
1338c2ecf20Sopenharmony_ci		pr_debug("PPid: string not found for pid %d\n", pid);
1348c2ecf20Sopenharmony_ci	}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci	return 0;
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic int perf_event__prepare_comm(union perf_event *event, pid_t pid,
1408c2ecf20Sopenharmony_ci				    struct machine *machine,
1418c2ecf20Sopenharmony_ci				    pid_t *tgid, pid_t *ppid)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	size_t size;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	*ppid = -1;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	memset(&event->comm, 0, sizeof(event->comm));
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (machine__is_host(machine)) {
1508c2ecf20Sopenharmony_ci		if (perf_event__get_comm_ids(pid, event->comm.comm,
1518c2ecf20Sopenharmony_ci					     sizeof(event->comm.comm),
1528c2ecf20Sopenharmony_ci					     tgid, ppid) != 0) {
1538c2ecf20Sopenharmony_ci			return -1;
1548c2ecf20Sopenharmony_ci		}
1558c2ecf20Sopenharmony_ci	} else {
1568c2ecf20Sopenharmony_ci		*tgid = machine->pid;
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	if (*tgid < 0)
1608c2ecf20Sopenharmony_ci		return -1;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	event->comm.pid = *tgid;
1638c2ecf20Sopenharmony_ci	event->comm.header.type = PERF_RECORD_COMM;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	size = strlen(event->comm.comm) + 1;
1668c2ecf20Sopenharmony_ci	size = PERF_ALIGN(size, sizeof(u64));
1678c2ecf20Sopenharmony_ci	memset(event->comm.comm + size, 0, machine->id_hdr_size);
1688c2ecf20Sopenharmony_ci	event->comm.header.size = (sizeof(event->comm) -
1698c2ecf20Sopenharmony_ci				(sizeof(event->comm.comm) - size) +
1708c2ecf20Sopenharmony_ci				machine->id_hdr_size);
1718c2ecf20Sopenharmony_ci	event->comm.tid = pid;
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci	return 0;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cipid_t perf_event__synthesize_comm(struct perf_tool *tool,
1778c2ecf20Sopenharmony_ci					 union perf_event *event, pid_t pid,
1788c2ecf20Sopenharmony_ci					 perf_event__handler_t process,
1798c2ecf20Sopenharmony_ci					 struct machine *machine)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	pid_t tgid, ppid;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (perf_event__prepare_comm(event, pid, machine, &tgid, &ppid) != 0)
1848c2ecf20Sopenharmony_ci		return -1;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
1878c2ecf20Sopenharmony_ci		return -1;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return tgid;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic void perf_event__get_ns_link_info(pid_t pid, const char *ns,
1938c2ecf20Sopenharmony_ci					 struct perf_ns_link_info *ns_link_info)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	struct stat64 st;
1968c2ecf20Sopenharmony_ci	char proc_ns[128];
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	sprintf(proc_ns, "/proc/%u/ns/%s", pid, ns);
1998c2ecf20Sopenharmony_ci	if (stat64(proc_ns, &st) == 0) {
2008c2ecf20Sopenharmony_ci		ns_link_info->dev = st.st_dev;
2018c2ecf20Sopenharmony_ci		ns_link_info->ino = st.st_ino;
2028c2ecf20Sopenharmony_ci	}
2038c2ecf20Sopenharmony_ci}
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ciint perf_event__synthesize_namespaces(struct perf_tool *tool,
2068c2ecf20Sopenharmony_ci				      union perf_event *event,
2078c2ecf20Sopenharmony_ci				      pid_t pid, pid_t tgid,
2088c2ecf20Sopenharmony_ci				      perf_event__handler_t process,
2098c2ecf20Sopenharmony_ci				      struct machine *machine)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	u32 idx;
2128c2ecf20Sopenharmony_ci	struct perf_ns_link_info *ns_link_info;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	if (!tool || !tool->namespace_events)
2158c2ecf20Sopenharmony_ci		return 0;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	memset(&event->namespaces, 0, (sizeof(event->namespaces) +
2188c2ecf20Sopenharmony_ci	       (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
2198c2ecf20Sopenharmony_ci	       machine->id_hdr_size));
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	event->namespaces.pid = tgid;
2228c2ecf20Sopenharmony_ci	event->namespaces.tid = pid;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	event->namespaces.nr_namespaces = NR_NAMESPACES;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	ns_link_info = event->namespaces.link_info;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	for (idx = 0; idx < event->namespaces.nr_namespaces; idx++)
2298c2ecf20Sopenharmony_ci		perf_event__get_ns_link_info(pid, perf_ns__name(idx),
2308c2ecf20Sopenharmony_ci					     &ns_link_info[idx]);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	event->namespaces.header.type = PERF_RECORD_NAMESPACES;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	event->namespaces.header.size = (sizeof(event->namespaces) +
2358c2ecf20Sopenharmony_ci			(NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
2368c2ecf20Sopenharmony_ci			machine->id_hdr_size);
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
2398c2ecf20Sopenharmony_ci		return -1;
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	return 0;
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic int perf_event__synthesize_fork(struct perf_tool *tool,
2458c2ecf20Sopenharmony_ci				       union perf_event *event,
2468c2ecf20Sopenharmony_ci				       pid_t pid, pid_t tgid, pid_t ppid,
2478c2ecf20Sopenharmony_ci				       perf_event__handler_t process,
2488c2ecf20Sopenharmony_ci				       struct machine *machine)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	memset(&event->fork, 0, sizeof(event->fork) + machine->id_hdr_size);
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	/*
2538c2ecf20Sopenharmony_ci	 * for main thread set parent to ppid from status file. For other
2548c2ecf20Sopenharmony_ci	 * threads set parent pid to main thread. ie., assume main thread
2558c2ecf20Sopenharmony_ci	 * spawns all threads in a process
2568c2ecf20Sopenharmony_ci	*/
2578c2ecf20Sopenharmony_ci	if (tgid == pid) {
2588c2ecf20Sopenharmony_ci		event->fork.ppid = ppid;
2598c2ecf20Sopenharmony_ci		event->fork.ptid = ppid;
2608c2ecf20Sopenharmony_ci	} else {
2618c2ecf20Sopenharmony_ci		event->fork.ppid = tgid;
2628c2ecf20Sopenharmony_ci		event->fork.ptid = tgid;
2638c2ecf20Sopenharmony_ci	}
2648c2ecf20Sopenharmony_ci	event->fork.pid  = tgid;
2658c2ecf20Sopenharmony_ci	event->fork.tid  = pid;
2668c2ecf20Sopenharmony_ci	event->fork.header.type = PERF_RECORD_FORK;
2678c2ecf20Sopenharmony_ci	event->fork.header.misc = PERF_RECORD_MISC_FORK_EXEC;
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	event->fork.header.size = (sizeof(event->fork) + machine->id_hdr_size);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (perf_tool__process_synth_event(tool, event, machine, process) != 0)
2728c2ecf20Sopenharmony_ci		return -1;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	return 0;
2758c2ecf20Sopenharmony_ci}
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic bool read_proc_maps_line(struct io *io, __u64 *start, __u64 *end,
2788c2ecf20Sopenharmony_ci				u32 *prot, u32 *flags, __u64 *offset,
2798c2ecf20Sopenharmony_ci				u32 *maj, u32 *min,
2808c2ecf20Sopenharmony_ci				__u64 *inode,
2818c2ecf20Sopenharmony_ci				ssize_t pathname_size, char *pathname)
2828c2ecf20Sopenharmony_ci{
2838c2ecf20Sopenharmony_ci	__u64 temp;
2848c2ecf20Sopenharmony_ci	int ch;
2858c2ecf20Sopenharmony_ci	char *start_pathname = pathname;
2868c2ecf20Sopenharmony_ci
2878c2ecf20Sopenharmony_ci	if (io__get_hex(io, start) != '-')
2888c2ecf20Sopenharmony_ci		return false;
2898c2ecf20Sopenharmony_ci	if (io__get_hex(io, end) != ' ')
2908c2ecf20Sopenharmony_ci		return false;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	/* map protection and flags bits */
2938c2ecf20Sopenharmony_ci	*prot = 0;
2948c2ecf20Sopenharmony_ci	ch = io__get_char(io);
2958c2ecf20Sopenharmony_ci	if (ch == 'r')
2968c2ecf20Sopenharmony_ci		*prot |= PROT_READ;
2978c2ecf20Sopenharmony_ci	else if (ch != '-')
2988c2ecf20Sopenharmony_ci		return false;
2998c2ecf20Sopenharmony_ci	ch = io__get_char(io);
3008c2ecf20Sopenharmony_ci	if (ch == 'w')
3018c2ecf20Sopenharmony_ci		*prot |= PROT_WRITE;
3028c2ecf20Sopenharmony_ci	else if (ch != '-')
3038c2ecf20Sopenharmony_ci		return false;
3048c2ecf20Sopenharmony_ci	ch = io__get_char(io);
3058c2ecf20Sopenharmony_ci	if (ch == 'x')
3068c2ecf20Sopenharmony_ci		*prot |= PROT_EXEC;
3078c2ecf20Sopenharmony_ci	else if (ch != '-')
3088c2ecf20Sopenharmony_ci		return false;
3098c2ecf20Sopenharmony_ci	ch = io__get_char(io);
3108c2ecf20Sopenharmony_ci	if (ch == 's')
3118c2ecf20Sopenharmony_ci		*flags = MAP_SHARED;
3128c2ecf20Sopenharmony_ci	else if (ch == 'p')
3138c2ecf20Sopenharmony_ci		*flags = MAP_PRIVATE;
3148c2ecf20Sopenharmony_ci	else
3158c2ecf20Sopenharmony_ci		return false;
3168c2ecf20Sopenharmony_ci	if (io__get_char(io) != ' ')
3178c2ecf20Sopenharmony_ci		return false;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	if (io__get_hex(io, offset) != ' ')
3208c2ecf20Sopenharmony_ci		return false;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	if (io__get_hex(io, &temp) != ':')
3238c2ecf20Sopenharmony_ci		return false;
3248c2ecf20Sopenharmony_ci	*maj = temp;
3258c2ecf20Sopenharmony_ci	if (io__get_hex(io, &temp) != ' ')
3268c2ecf20Sopenharmony_ci		return false;
3278c2ecf20Sopenharmony_ci	*min = temp;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci	ch = io__get_dec(io, inode);
3308c2ecf20Sopenharmony_ci	if (ch != ' ') {
3318c2ecf20Sopenharmony_ci		*pathname = '\0';
3328c2ecf20Sopenharmony_ci		return ch == '\n';
3338c2ecf20Sopenharmony_ci	}
3348c2ecf20Sopenharmony_ci	do {
3358c2ecf20Sopenharmony_ci		ch = io__get_char(io);
3368c2ecf20Sopenharmony_ci	} while (ch == ' ');
3378c2ecf20Sopenharmony_ci	while (true) {
3388c2ecf20Sopenharmony_ci		if (ch < 0)
3398c2ecf20Sopenharmony_ci			return false;
3408c2ecf20Sopenharmony_ci		if (ch == '\0' || ch == '\n' ||
3418c2ecf20Sopenharmony_ci		    (pathname + 1 - start_pathname) >= pathname_size) {
3428c2ecf20Sopenharmony_ci			*pathname = '\0';
3438c2ecf20Sopenharmony_ci			return true;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci		*pathname++ = ch;
3468c2ecf20Sopenharmony_ci		ch = io__get_char(io);
3478c2ecf20Sopenharmony_ci	}
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ciint perf_event__synthesize_mmap_events(struct perf_tool *tool,
3518c2ecf20Sopenharmony_ci				       union perf_event *event,
3528c2ecf20Sopenharmony_ci				       pid_t pid, pid_t tgid,
3538c2ecf20Sopenharmony_ci				       perf_event__handler_t process,
3548c2ecf20Sopenharmony_ci				       struct machine *machine,
3558c2ecf20Sopenharmony_ci				       bool mmap_data)
3568c2ecf20Sopenharmony_ci{
3578c2ecf20Sopenharmony_ci	unsigned long long t;
3588c2ecf20Sopenharmony_ci	char bf[BUFSIZ];
3598c2ecf20Sopenharmony_ci	struct io io;
3608c2ecf20Sopenharmony_ci	bool truncation = false;
3618c2ecf20Sopenharmony_ci	unsigned long long timeout = proc_map_timeout * 1000000ULL;
3628c2ecf20Sopenharmony_ci	int rc = 0;
3638c2ecf20Sopenharmony_ci	const char *hugetlbfs_mnt = hugetlbfs__mountpoint();
3648c2ecf20Sopenharmony_ci	int hugetlbfs_mnt_len = hugetlbfs_mnt ? strlen(hugetlbfs_mnt) : 0;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	if (machine__is_default_guest(machine))
3678c2ecf20Sopenharmony_ci		return 0;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	snprintf(bf, sizeof(bf), "%s/proc/%d/task/%d/maps",
3708c2ecf20Sopenharmony_ci		machine->root_dir, pid, pid);
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	io.fd = open(bf, O_RDONLY, 0);
3738c2ecf20Sopenharmony_ci	if (io.fd < 0) {
3748c2ecf20Sopenharmony_ci		/*
3758c2ecf20Sopenharmony_ci		 * We raced with a task exiting - just return:
3768c2ecf20Sopenharmony_ci		 */
3778c2ecf20Sopenharmony_ci		pr_debug("couldn't open %s\n", bf);
3788c2ecf20Sopenharmony_ci		return -1;
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	io__init(&io, io.fd, bf, sizeof(bf));
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	event->header.type = PERF_RECORD_MMAP2;
3838c2ecf20Sopenharmony_ci	t = rdclock();
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	while (!io.eof) {
3868c2ecf20Sopenharmony_ci		static const char anonstr[] = "//anon";
3878c2ecf20Sopenharmony_ci		size_t size, aligned_size;
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		/* ensure null termination since stack will be reused. */
3908c2ecf20Sopenharmony_ci		event->mmap2.filename[0] = '\0';
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci		/* 00400000-0040c000 r-xp 00000000 fd:01 41038  /bin/cat */
3938c2ecf20Sopenharmony_ci		if (!read_proc_maps_line(&io,
3948c2ecf20Sopenharmony_ci					&event->mmap2.start,
3958c2ecf20Sopenharmony_ci					&event->mmap2.len,
3968c2ecf20Sopenharmony_ci					&event->mmap2.prot,
3978c2ecf20Sopenharmony_ci					&event->mmap2.flags,
3988c2ecf20Sopenharmony_ci					&event->mmap2.pgoff,
3998c2ecf20Sopenharmony_ci					&event->mmap2.maj,
4008c2ecf20Sopenharmony_ci					&event->mmap2.min,
4018c2ecf20Sopenharmony_ci					&event->mmap2.ino,
4028c2ecf20Sopenharmony_ci					sizeof(event->mmap2.filename),
4038c2ecf20Sopenharmony_ci					event->mmap2.filename))
4048c2ecf20Sopenharmony_ci			continue;
4058c2ecf20Sopenharmony_ci
4068c2ecf20Sopenharmony_ci		if ((rdclock() - t) > timeout) {
4078c2ecf20Sopenharmony_ci			pr_warning("Reading %s/proc/%d/task/%d/maps time out. "
4088c2ecf20Sopenharmony_ci				   "You may want to increase "
4098c2ecf20Sopenharmony_ci				   "the time limit by --proc-map-timeout\n",
4108c2ecf20Sopenharmony_ci				   machine->root_dir, pid, pid);
4118c2ecf20Sopenharmony_ci			truncation = true;
4128c2ecf20Sopenharmony_ci			goto out;
4138c2ecf20Sopenharmony_ci		}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci		event->mmap2.ino_generation = 0;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci		/*
4188c2ecf20Sopenharmony_ci		 * Just like the kernel, see __perf_event_mmap in kernel/perf_event.c
4198c2ecf20Sopenharmony_ci		 */
4208c2ecf20Sopenharmony_ci		if (machine__is_host(machine))
4218c2ecf20Sopenharmony_ci			event->header.misc = PERF_RECORD_MISC_USER;
4228c2ecf20Sopenharmony_ci		else
4238c2ecf20Sopenharmony_ci			event->header.misc = PERF_RECORD_MISC_GUEST_USER;
4248c2ecf20Sopenharmony_ci
4258c2ecf20Sopenharmony_ci		if ((event->mmap2.prot & PROT_EXEC) == 0) {
4268c2ecf20Sopenharmony_ci			if (!mmap_data || (event->mmap2.prot & PROT_READ) == 0)
4278c2ecf20Sopenharmony_ci				continue;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci			event->header.misc |= PERF_RECORD_MISC_MMAP_DATA;
4308c2ecf20Sopenharmony_ci		}
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ciout:
4338c2ecf20Sopenharmony_ci		if (truncation)
4348c2ecf20Sopenharmony_ci			event->header.misc |= PERF_RECORD_MISC_PROC_MAP_PARSE_TIMEOUT;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		if (!strcmp(event->mmap2.filename, ""))
4378c2ecf20Sopenharmony_ci			strcpy(event->mmap2.filename, anonstr);
4388c2ecf20Sopenharmony_ci
4398c2ecf20Sopenharmony_ci		if (hugetlbfs_mnt_len &&
4408c2ecf20Sopenharmony_ci		    !strncmp(event->mmap2.filename, hugetlbfs_mnt,
4418c2ecf20Sopenharmony_ci			     hugetlbfs_mnt_len)) {
4428c2ecf20Sopenharmony_ci			strcpy(event->mmap2.filename, anonstr);
4438c2ecf20Sopenharmony_ci			event->mmap2.flags |= MAP_HUGETLB;
4448c2ecf20Sopenharmony_ci		}
4458c2ecf20Sopenharmony_ci
4468c2ecf20Sopenharmony_ci		size = strlen(event->mmap2.filename) + 1;
4478c2ecf20Sopenharmony_ci		aligned_size = PERF_ALIGN(size, sizeof(u64));
4488c2ecf20Sopenharmony_ci		event->mmap2.len -= event->mmap.start;
4498c2ecf20Sopenharmony_ci		event->mmap2.header.size = (sizeof(event->mmap2) -
4508c2ecf20Sopenharmony_ci					(sizeof(event->mmap2.filename) - aligned_size));
4518c2ecf20Sopenharmony_ci		memset(event->mmap2.filename + size, 0, machine->id_hdr_size +
4528c2ecf20Sopenharmony_ci			(aligned_size - size));
4538c2ecf20Sopenharmony_ci		event->mmap2.header.size += machine->id_hdr_size;
4548c2ecf20Sopenharmony_ci		event->mmap2.pid = tgid;
4558c2ecf20Sopenharmony_ci		event->mmap2.tid = pid;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci		if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
4588c2ecf20Sopenharmony_ci			rc = -1;
4598c2ecf20Sopenharmony_ci			break;
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci		if (truncation)
4638c2ecf20Sopenharmony_ci			break;
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	close(io.fd);
4678c2ecf20Sopenharmony_ci	return rc;
4688c2ecf20Sopenharmony_ci}
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci#ifdef HAVE_FILE_HANDLE
4718c2ecf20Sopenharmony_cistatic int perf_event__synthesize_cgroup(struct perf_tool *tool,
4728c2ecf20Sopenharmony_ci					 union perf_event *event,
4738c2ecf20Sopenharmony_ci					 char *path, size_t mount_len,
4748c2ecf20Sopenharmony_ci					 perf_event__handler_t process,
4758c2ecf20Sopenharmony_ci					 struct machine *machine)
4768c2ecf20Sopenharmony_ci{
4778c2ecf20Sopenharmony_ci	size_t event_size = sizeof(event->cgroup) - sizeof(event->cgroup.path);
4788c2ecf20Sopenharmony_ci	size_t path_len = strlen(path) - mount_len + 1;
4798c2ecf20Sopenharmony_ci	struct {
4808c2ecf20Sopenharmony_ci		struct file_handle fh;
4818c2ecf20Sopenharmony_ci		uint64_t cgroup_id;
4828c2ecf20Sopenharmony_ci	} handle;
4838c2ecf20Sopenharmony_ci	int mount_id;
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci	while (path_len % sizeof(u64))
4868c2ecf20Sopenharmony_ci		path[mount_len + path_len++] = '\0';
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	memset(&event->cgroup, 0, event_size);
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_ci	event->cgroup.header.type = PERF_RECORD_CGROUP;
4918c2ecf20Sopenharmony_ci	event->cgroup.header.size = event_size + path_len + machine->id_hdr_size;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	handle.fh.handle_bytes = sizeof(handle.cgroup_id);
4948c2ecf20Sopenharmony_ci	if (name_to_handle_at(AT_FDCWD, path, &handle.fh, &mount_id, 0) < 0) {
4958c2ecf20Sopenharmony_ci		pr_debug("stat failed: %s\n", path);
4968c2ecf20Sopenharmony_ci		return -1;
4978c2ecf20Sopenharmony_ci	}
4988c2ecf20Sopenharmony_ci
4998c2ecf20Sopenharmony_ci	event->cgroup.id = handle.cgroup_id;
5008c2ecf20Sopenharmony_ci	strncpy(event->cgroup.path, path + mount_len, path_len);
5018c2ecf20Sopenharmony_ci	memset(event->cgroup.path + path_len, 0, machine->id_hdr_size);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	if (perf_tool__process_synth_event(tool, event, machine, process) < 0) {
5048c2ecf20Sopenharmony_ci		pr_debug("process synth event failed\n");
5058c2ecf20Sopenharmony_ci		return -1;
5068c2ecf20Sopenharmony_ci	}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci	return 0;
5098c2ecf20Sopenharmony_ci}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_cistatic int perf_event__walk_cgroup_tree(struct perf_tool *tool,
5128c2ecf20Sopenharmony_ci					union perf_event *event,
5138c2ecf20Sopenharmony_ci					char *path, size_t mount_len,
5148c2ecf20Sopenharmony_ci					perf_event__handler_t process,
5158c2ecf20Sopenharmony_ci					struct machine *machine)
5168c2ecf20Sopenharmony_ci{
5178c2ecf20Sopenharmony_ci	size_t pos = strlen(path);
5188c2ecf20Sopenharmony_ci	DIR *d;
5198c2ecf20Sopenharmony_ci	struct dirent *dent;
5208c2ecf20Sopenharmony_ci	int ret = 0;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (perf_event__synthesize_cgroup(tool, event, path, mount_len,
5238c2ecf20Sopenharmony_ci					  process, machine) < 0)
5248c2ecf20Sopenharmony_ci		return -1;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	d = opendir(path);
5278c2ecf20Sopenharmony_ci	if (d == NULL) {
5288c2ecf20Sopenharmony_ci		pr_debug("failed to open directory: %s\n", path);
5298c2ecf20Sopenharmony_ci		return -1;
5308c2ecf20Sopenharmony_ci	}
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	while ((dent = readdir(d)) != NULL) {
5338c2ecf20Sopenharmony_ci		if (dent->d_type != DT_DIR)
5348c2ecf20Sopenharmony_ci			continue;
5358c2ecf20Sopenharmony_ci		if (!strcmp(dent->d_name, ".") ||
5368c2ecf20Sopenharmony_ci		    !strcmp(dent->d_name, ".."))
5378c2ecf20Sopenharmony_ci			continue;
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci		/* any sane path should be less than PATH_MAX */
5408c2ecf20Sopenharmony_ci		if (strlen(path) + strlen(dent->d_name) + 1 >= PATH_MAX)
5418c2ecf20Sopenharmony_ci			continue;
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_ci		if (path[pos - 1] != '/')
5448c2ecf20Sopenharmony_ci			strcat(path, "/");
5458c2ecf20Sopenharmony_ci		strcat(path, dent->d_name);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci		ret = perf_event__walk_cgroup_tree(tool, event, path,
5488c2ecf20Sopenharmony_ci						   mount_len, process, machine);
5498c2ecf20Sopenharmony_ci		if (ret < 0)
5508c2ecf20Sopenharmony_ci			break;
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci		path[pos] = '\0';
5538c2ecf20Sopenharmony_ci	}
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	closedir(d);
5568c2ecf20Sopenharmony_ci	return ret;
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ciint perf_event__synthesize_cgroups(struct perf_tool *tool,
5608c2ecf20Sopenharmony_ci				   perf_event__handler_t process,
5618c2ecf20Sopenharmony_ci				   struct machine *machine)
5628c2ecf20Sopenharmony_ci{
5638c2ecf20Sopenharmony_ci	union perf_event event;
5648c2ecf20Sopenharmony_ci	char cgrp_root[PATH_MAX];
5658c2ecf20Sopenharmony_ci	size_t mount_len;  /* length of mount point in the path */
5668c2ecf20Sopenharmony_ci
5678c2ecf20Sopenharmony_ci	if (!tool || !tool->cgroup_events)
5688c2ecf20Sopenharmony_ci		return 0;
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci	if (cgroupfs_find_mountpoint(cgrp_root, PATH_MAX, "perf_event") < 0) {
5718c2ecf20Sopenharmony_ci		pr_debug("cannot find cgroup mount point\n");
5728c2ecf20Sopenharmony_ci		return -1;
5738c2ecf20Sopenharmony_ci	}
5748c2ecf20Sopenharmony_ci
5758c2ecf20Sopenharmony_ci	mount_len = strlen(cgrp_root);
5768c2ecf20Sopenharmony_ci	/* make sure the path starts with a slash (after mount point) */
5778c2ecf20Sopenharmony_ci	strcat(cgrp_root, "/");
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	if (perf_event__walk_cgroup_tree(tool, &event, cgrp_root, mount_len,
5808c2ecf20Sopenharmony_ci					 process, machine) < 0)
5818c2ecf20Sopenharmony_ci		return -1;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	return 0;
5848c2ecf20Sopenharmony_ci}
5858c2ecf20Sopenharmony_ci#else
5868c2ecf20Sopenharmony_ciint perf_event__synthesize_cgroups(struct perf_tool *tool __maybe_unused,
5878c2ecf20Sopenharmony_ci				   perf_event__handler_t process __maybe_unused,
5888c2ecf20Sopenharmony_ci				   struct machine *machine __maybe_unused)
5898c2ecf20Sopenharmony_ci{
5908c2ecf20Sopenharmony_ci	return -1;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci#endif
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ciint perf_event__synthesize_modules(struct perf_tool *tool, perf_event__handler_t process,
5958c2ecf20Sopenharmony_ci				   struct machine *machine)
5968c2ecf20Sopenharmony_ci{
5978c2ecf20Sopenharmony_ci	int rc = 0;
5988c2ecf20Sopenharmony_ci	struct map *pos;
5998c2ecf20Sopenharmony_ci	struct maps *maps = machine__kernel_maps(machine);
6008c2ecf20Sopenharmony_ci	union perf_event *event = zalloc((sizeof(event->mmap) +
6018c2ecf20Sopenharmony_ci					  machine->id_hdr_size));
6028c2ecf20Sopenharmony_ci	if (event == NULL) {
6038c2ecf20Sopenharmony_ci		pr_debug("Not enough memory synthesizing mmap event "
6048c2ecf20Sopenharmony_ci			 "for kernel modules\n");
6058c2ecf20Sopenharmony_ci		return -1;
6068c2ecf20Sopenharmony_ci	}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	event->header.type = PERF_RECORD_MMAP;
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	/*
6118c2ecf20Sopenharmony_ci	 * kernel uses 0 for user space maps, see kernel/perf_event.c
6128c2ecf20Sopenharmony_ci	 * __perf_event_mmap
6138c2ecf20Sopenharmony_ci	 */
6148c2ecf20Sopenharmony_ci	if (machine__is_host(machine))
6158c2ecf20Sopenharmony_ci		event->header.misc = PERF_RECORD_MISC_KERNEL;
6168c2ecf20Sopenharmony_ci	else
6178c2ecf20Sopenharmony_ci		event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	maps__for_each_entry(maps, pos) {
6208c2ecf20Sopenharmony_ci		size_t size;
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_ci		if (!__map__is_kmodule(pos))
6238c2ecf20Sopenharmony_ci			continue;
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci		size = PERF_ALIGN(pos->dso->long_name_len + 1, sizeof(u64));
6268c2ecf20Sopenharmony_ci		event->mmap.header.type = PERF_RECORD_MMAP;
6278c2ecf20Sopenharmony_ci		event->mmap.header.size = (sizeof(event->mmap) -
6288c2ecf20Sopenharmony_ci				        (sizeof(event->mmap.filename) - size));
6298c2ecf20Sopenharmony_ci		memset(event->mmap.filename + size, 0, machine->id_hdr_size);
6308c2ecf20Sopenharmony_ci		event->mmap.header.size += machine->id_hdr_size;
6318c2ecf20Sopenharmony_ci		event->mmap.start = pos->start;
6328c2ecf20Sopenharmony_ci		event->mmap.len   = pos->end - pos->start;
6338c2ecf20Sopenharmony_ci		event->mmap.pid   = machine->pid;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci		memcpy(event->mmap.filename, pos->dso->long_name,
6368c2ecf20Sopenharmony_ci		       pos->dso->long_name_len + 1);
6378c2ecf20Sopenharmony_ci		if (perf_tool__process_synth_event(tool, event, machine, process) != 0) {
6388c2ecf20Sopenharmony_ci			rc = -1;
6398c2ecf20Sopenharmony_ci			break;
6408c2ecf20Sopenharmony_ci		}
6418c2ecf20Sopenharmony_ci	}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	free(event);
6448c2ecf20Sopenharmony_ci	return rc;
6458c2ecf20Sopenharmony_ci}
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_cistatic int __event__synthesize_thread(union perf_event *comm_event,
6488c2ecf20Sopenharmony_ci				      union perf_event *mmap_event,
6498c2ecf20Sopenharmony_ci				      union perf_event *fork_event,
6508c2ecf20Sopenharmony_ci				      union perf_event *namespaces_event,
6518c2ecf20Sopenharmony_ci				      pid_t pid, int full, perf_event__handler_t process,
6528c2ecf20Sopenharmony_ci				      struct perf_tool *tool, struct machine *machine, bool mmap_data)
6538c2ecf20Sopenharmony_ci{
6548c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
6558c2ecf20Sopenharmony_ci	DIR *tasks;
6568c2ecf20Sopenharmony_ci	struct dirent *dirent;
6578c2ecf20Sopenharmony_ci	pid_t tgid, ppid;
6588c2ecf20Sopenharmony_ci	int rc = 0;
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* special case: only send one comm event using passed in pid */
6618c2ecf20Sopenharmony_ci	if (!full) {
6628c2ecf20Sopenharmony_ci		tgid = perf_event__synthesize_comm(tool, comm_event, pid,
6638c2ecf20Sopenharmony_ci						   process, machine);
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_ci		if (tgid == -1)
6668c2ecf20Sopenharmony_ci			return -1;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci		if (perf_event__synthesize_namespaces(tool, namespaces_event, pid,
6698c2ecf20Sopenharmony_ci						      tgid, process, machine) < 0)
6708c2ecf20Sopenharmony_ci			return -1;
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci		/*
6738c2ecf20Sopenharmony_ci		 * send mmap only for thread group leader
6748c2ecf20Sopenharmony_ci		 * see thread__init_maps()
6758c2ecf20Sopenharmony_ci		 */
6768c2ecf20Sopenharmony_ci		if (pid == tgid &&
6778c2ecf20Sopenharmony_ci		    perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
6788c2ecf20Sopenharmony_ci						       process, machine, mmap_data))
6798c2ecf20Sopenharmony_ci			return -1;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci		return 0;
6828c2ecf20Sopenharmony_ci	}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	if (machine__is_default_guest(machine))
6858c2ecf20Sopenharmony_ci		return 0;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	snprintf(filename, sizeof(filename), "%s/proc/%d/task",
6888c2ecf20Sopenharmony_ci		 machine->root_dir, pid);
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	tasks = opendir(filename);
6918c2ecf20Sopenharmony_ci	if (tasks == NULL) {
6928c2ecf20Sopenharmony_ci		pr_debug("couldn't open %s\n", filename);
6938c2ecf20Sopenharmony_ci		return 0;
6948c2ecf20Sopenharmony_ci	}
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	while ((dirent = readdir(tasks)) != NULL) {
6978c2ecf20Sopenharmony_ci		char *end;
6988c2ecf20Sopenharmony_ci		pid_t _pid;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci		_pid = strtol(dirent->d_name, &end, 10);
7018c2ecf20Sopenharmony_ci		if (*end)
7028c2ecf20Sopenharmony_ci			continue;
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci		rc = -1;
7058c2ecf20Sopenharmony_ci		if (perf_event__prepare_comm(comm_event, _pid, machine,
7068c2ecf20Sopenharmony_ci					     &tgid, &ppid) != 0)
7078c2ecf20Sopenharmony_ci			break;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci		if (perf_event__synthesize_fork(tool, fork_event, _pid, tgid,
7108c2ecf20Sopenharmony_ci						ppid, process, machine) < 0)
7118c2ecf20Sopenharmony_ci			break;
7128c2ecf20Sopenharmony_ci
7138c2ecf20Sopenharmony_ci		if (perf_event__synthesize_namespaces(tool, namespaces_event, _pid,
7148c2ecf20Sopenharmony_ci						      tgid, process, machine) < 0)
7158c2ecf20Sopenharmony_ci			break;
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci		/*
7188c2ecf20Sopenharmony_ci		 * Send the prepared comm event
7198c2ecf20Sopenharmony_ci		 */
7208c2ecf20Sopenharmony_ci		if (perf_tool__process_synth_event(tool, comm_event, machine, process) != 0)
7218c2ecf20Sopenharmony_ci			break;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci		rc = 0;
7248c2ecf20Sopenharmony_ci		if (_pid == pid) {
7258c2ecf20Sopenharmony_ci			/* process the parent's maps too */
7268c2ecf20Sopenharmony_ci			rc = perf_event__synthesize_mmap_events(tool, mmap_event, pid, tgid,
7278c2ecf20Sopenharmony_ci						process, machine, mmap_data);
7288c2ecf20Sopenharmony_ci			if (rc)
7298c2ecf20Sopenharmony_ci				break;
7308c2ecf20Sopenharmony_ci		}
7318c2ecf20Sopenharmony_ci	}
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	closedir(tasks);
7348c2ecf20Sopenharmony_ci	return rc;
7358c2ecf20Sopenharmony_ci}
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ciint perf_event__synthesize_thread_map(struct perf_tool *tool,
7388c2ecf20Sopenharmony_ci				      struct perf_thread_map *threads,
7398c2ecf20Sopenharmony_ci				      perf_event__handler_t process,
7408c2ecf20Sopenharmony_ci				      struct machine *machine,
7418c2ecf20Sopenharmony_ci				      bool mmap_data)
7428c2ecf20Sopenharmony_ci{
7438c2ecf20Sopenharmony_ci	union perf_event *comm_event, *mmap_event, *fork_event;
7448c2ecf20Sopenharmony_ci	union perf_event *namespaces_event;
7458c2ecf20Sopenharmony_ci	int err = -1, thread, j;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
7488c2ecf20Sopenharmony_ci	if (comm_event == NULL)
7498c2ecf20Sopenharmony_ci		goto out;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci	mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
7528c2ecf20Sopenharmony_ci	if (mmap_event == NULL)
7538c2ecf20Sopenharmony_ci		goto out_free_comm;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
7568c2ecf20Sopenharmony_ci	if (fork_event == NULL)
7578c2ecf20Sopenharmony_ci		goto out_free_mmap;
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
7608c2ecf20Sopenharmony_ci				  (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
7618c2ecf20Sopenharmony_ci				  machine->id_hdr_size);
7628c2ecf20Sopenharmony_ci	if (namespaces_event == NULL)
7638c2ecf20Sopenharmony_ci		goto out_free_fork;
7648c2ecf20Sopenharmony_ci
7658c2ecf20Sopenharmony_ci	err = 0;
7668c2ecf20Sopenharmony_ci	for (thread = 0; thread < threads->nr; ++thread) {
7678c2ecf20Sopenharmony_ci		if (__event__synthesize_thread(comm_event, mmap_event,
7688c2ecf20Sopenharmony_ci					       fork_event, namespaces_event,
7698c2ecf20Sopenharmony_ci					       perf_thread_map__pid(threads, thread), 0,
7708c2ecf20Sopenharmony_ci					       process, tool, machine,
7718c2ecf20Sopenharmony_ci					       mmap_data)) {
7728c2ecf20Sopenharmony_ci			err = -1;
7738c2ecf20Sopenharmony_ci			break;
7748c2ecf20Sopenharmony_ci		}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_ci		/*
7778c2ecf20Sopenharmony_ci		 * comm.pid is set to thread group id by
7788c2ecf20Sopenharmony_ci		 * perf_event__synthesize_comm
7798c2ecf20Sopenharmony_ci		 */
7808c2ecf20Sopenharmony_ci		if ((int) comm_event->comm.pid != perf_thread_map__pid(threads, thread)) {
7818c2ecf20Sopenharmony_ci			bool need_leader = true;
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_ci			/* is thread group leader in thread_map? */
7848c2ecf20Sopenharmony_ci			for (j = 0; j < threads->nr; ++j) {
7858c2ecf20Sopenharmony_ci				if ((int) comm_event->comm.pid == perf_thread_map__pid(threads, j)) {
7868c2ecf20Sopenharmony_ci					need_leader = false;
7878c2ecf20Sopenharmony_ci					break;
7888c2ecf20Sopenharmony_ci				}
7898c2ecf20Sopenharmony_ci			}
7908c2ecf20Sopenharmony_ci
7918c2ecf20Sopenharmony_ci			/* if not, generate events for it */
7928c2ecf20Sopenharmony_ci			if (need_leader &&
7938c2ecf20Sopenharmony_ci			    __event__synthesize_thread(comm_event, mmap_event,
7948c2ecf20Sopenharmony_ci						       fork_event, namespaces_event,
7958c2ecf20Sopenharmony_ci						       comm_event->comm.pid, 0,
7968c2ecf20Sopenharmony_ci						       process, tool, machine,
7978c2ecf20Sopenharmony_ci						       mmap_data)) {
7988c2ecf20Sopenharmony_ci				err = -1;
7998c2ecf20Sopenharmony_ci				break;
8008c2ecf20Sopenharmony_ci			}
8018c2ecf20Sopenharmony_ci		}
8028c2ecf20Sopenharmony_ci	}
8038c2ecf20Sopenharmony_ci	free(namespaces_event);
8048c2ecf20Sopenharmony_ciout_free_fork:
8058c2ecf20Sopenharmony_ci	free(fork_event);
8068c2ecf20Sopenharmony_ciout_free_mmap:
8078c2ecf20Sopenharmony_ci	free(mmap_event);
8088c2ecf20Sopenharmony_ciout_free_comm:
8098c2ecf20Sopenharmony_ci	free(comm_event);
8108c2ecf20Sopenharmony_ciout:
8118c2ecf20Sopenharmony_ci	return err;
8128c2ecf20Sopenharmony_ci}
8138c2ecf20Sopenharmony_ci
8148c2ecf20Sopenharmony_cistatic int __perf_event__synthesize_threads(struct perf_tool *tool,
8158c2ecf20Sopenharmony_ci					    perf_event__handler_t process,
8168c2ecf20Sopenharmony_ci					    struct machine *machine,
8178c2ecf20Sopenharmony_ci					    bool mmap_data,
8188c2ecf20Sopenharmony_ci					    struct dirent **dirent,
8198c2ecf20Sopenharmony_ci					    int start,
8208c2ecf20Sopenharmony_ci					    int num)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	union perf_event *comm_event, *mmap_event, *fork_event;
8238c2ecf20Sopenharmony_ci	union perf_event *namespaces_event;
8248c2ecf20Sopenharmony_ci	int err = -1;
8258c2ecf20Sopenharmony_ci	char *end;
8268c2ecf20Sopenharmony_ci	pid_t pid;
8278c2ecf20Sopenharmony_ci	int i;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	comm_event = malloc(sizeof(comm_event->comm) + machine->id_hdr_size);
8308c2ecf20Sopenharmony_ci	if (comm_event == NULL)
8318c2ecf20Sopenharmony_ci		goto out;
8328c2ecf20Sopenharmony_ci
8338c2ecf20Sopenharmony_ci	mmap_event = malloc(sizeof(mmap_event->mmap2) + machine->id_hdr_size);
8348c2ecf20Sopenharmony_ci	if (mmap_event == NULL)
8358c2ecf20Sopenharmony_ci		goto out_free_comm;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	fork_event = malloc(sizeof(fork_event->fork) + machine->id_hdr_size);
8388c2ecf20Sopenharmony_ci	if (fork_event == NULL)
8398c2ecf20Sopenharmony_ci		goto out_free_mmap;
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_ci	namespaces_event = malloc(sizeof(namespaces_event->namespaces) +
8428c2ecf20Sopenharmony_ci				  (NR_NAMESPACES * sizeof(struct perf_ns_link_info)) +
8438c2ecf20Sopenharmony_ci				  machine->id_hdr_size);
8448c2ecf20Sopenharmony_ci	if (namespaces_event == NULL)
8458c2ecf20Sopenharmony_ci		goto out_free_fork;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	for (i = start; i < start + num; i++) {
8488c2ecf20Sopenharmony_ci		if (!isdigit(dirent[i]->d_name[0]))
8498c2ecf20Sopenharmony_ci			continue;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci		pid = (pid_t)strtol(dirent[i]->d_name, &end, 10);
8528c2ecf20Sopenharmony_ci		/* only interested in proper numerical dirents */
8538c2ecf20Sopenharmony_ci		if (*end)
8548c2ecf20Sopenharmony_ci			continue;
8558c2ecf20Sopenharmony_ci		/*
8568c2ecf20Sopenharmony_ci		 * We may race with exiting thread, so don't stop just because
8578c2ecf20Sopenharmony_ci		 * one thread couldn't be synthesized.
8588c2ecf20Sopenharmony_ci		 */
8598c2ecf20Sopenharmony_ci		__event__synthesize_thread(comm_event, mmap_event, fork_event,
8608c2ecf20Sopenharmony_ci					   namespaces_event, pid, 1, process,
8618c2ecf20Sopenharmony_ci					   tool, machine, mmap_data);
8628c2ecf20Sopenharmony_ci	}
8638c2ecf20Sopenharmony_ci	err = 0;
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci	free(namespaces_event);
8668c2ecf20Sopenharmony_ciout_free_fork:
8678c2ecf20Sopenharmony_ci	free(fork_event);
8688c2ecf20Sopenharmony_ciout_free_mmap:
8698c2ecf20Sopenharmony_ci	free(mmap_event);
8708c2ecf20Sopenharmony_ciout_free_comm:
8718c2ecf20Sopenharmony_ci	free(comm_event);
8728c2ecf20Sopenharmony_ciout:
8738c2ecf20Sopenharmony_ci	return err;
8748c2ecf20Sopenharmony_ci}
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_cistruct synthesize_threads_arg {
8778c2ecf20Sopenharmony_ci	struct perf_tool *tool;
8788c2ecf20Sopenharmony_ci	perf_event__handler_t process;
8798c2ecf20Sopenharmony_ci	struct machine *machine;
8808c2ecf20Sopenharmony_ci	bool mmap_data;
8818c2ecf20Sopenharmony_ci	struct dirent **dirent;
8828c2ecf20Sopenharmony_ci	int num;
8838c2ecf20Sopenharmony_ci	int start;
8848c2ecf20Sopenharmony_ci};
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic void *synthesize_threads_worker(void *arg)
8878c2ecf20Sopenharmony_ci{
8888c2ecf20Sopenharmony_ci	struct synthesize_threads_arg *args = arg;
8898c2ecf20Sopenharmony_ci
8908c2ecf20Sopenharmony_ci	__perf_event__synthesize_threads(args->tool, args->process,
8918c2ecf20Sopenharmony_ci					 args->machine, args->mmap_data,
8928c2ecf20Sopenharmony_ci					 args->dirent,
8938c2ecf20Sopenharmony_ci					 args->start, args->num);
8948c2ecf20Sopenharmony_ci	return NULL;
8958c2ecf20Sopenharmony_ci}
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ciint perf_event__synthesize_threads(struct perf_tool *tool,
8988c2ecf20Sopenharmony_ci				   perf_event__handler_t process,
8998c2ecf20Sopenharmony_ci				   struct machine *machine,
9008c2ecf20Sopenharmony_ci				   bool mmap_data,
9018c2ecf20Sopenharmony_ci				   unsigned int nr_threads_synthesize)
9028c2ecf20Sopenharmony_ci{
9038c2ecf20Sopenharmony_ci	struct synthesize_threads_arg *args = NULL;
9048c2ecf20Sopenharmony_ci	pthread_t *synthesize_threads = NULL;
9058c2ecf20Sopenharmony_ci	char proc_path[PATH_MAX];
9068c2ecf20Sopenharmony_ci	struct dirent **dirent;
9078c2ecf20Sopenharmony_ci	int num_per_thread;
9088c2ecf20Sopenharmony_ci	int m, n, i, j;
9098c2ecf20Sopenharmony_ci	int thread_nr;
9108c2ecf20Sopenharmony_ci	int base = 0;
9118c2ecf20Sopenharmony_ci	int err = -1;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	if (machine__is_default_guest(machine))
9158c2ecf20Sopenharmony_ci		return 0;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	snprintf(proc_path, sizeof(proc_path), "%s/proc", machine->root_dir);
9188c2ecf20Sopenharmony_ci	n = scandir(proc_path, &dirent, 0, alphasort);
9198c2ecf20Sopenharmony_ci	if (n < 0)
9208c2ecf20Sopenharmony_ci		return err;
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	if (nr_threads_synthesize == UINT_MAX)
9238c2ecf20Sopenharmony_ci		thread_nr = sysconf(_SC_NPROCESSORS_ONLN);
9248c2ecf20Sopenharmony_ci	else
9258c2ecf20Sopenharmony_ci		thread_nr = nr_threads_synthesize;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	if (thread_nr <= 1) {
9288c2ecf20Sopenharmony_ci		err = __perf_event__synthesize_threads(tool, process,
9298c2ecf20Sopenharmony_ci						       machine, mmap_data,
9308c2ecf20Sopenharmony_ci						       dirent, base, n);
9318c2ecf20Sopenharmony_ci		goto free_dirent;
9328c2ecf20Sopenharmony_ci	}
9338c2ecf20Sopenharmony_ci	if (thread_nr > n)
9348c2ecf20Sopenharmony_ci		thread_nr = n;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	synthesize_threads = calloc(sizeof(pthread_t), thread_nr);
9378c2ecf20Sopenharmony_ci	if (synthesize_threads == NULL)
9388c2ecf20Sopenharmony_ci		goto free_dirent;
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	args = calloc(sizeof(*args), thread_nr);
9418c2ecf20Sopenharmony_ci	if (args == NULL)
9428c2ecf20Sopenharmony_ci		goto free_threads;
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci	num_per_thread = n / thread_nr;
9458c2ecf20Sopenharmony_ci	m = n % thread_nr;
9468c2ecf20Sopenharmony_ci	for (i = 0; i < thread_nr; i++) {
9478c2ecf20Sopenharmony_ci		args[i].tool = tool;
9488c2ecf20Sopenharmony_ci		args[i].process = process;
9498c2ecf20Sopenharmony_ci		args[i].machine = machine;
9508c2ecf20Sopenharmony_ci		args[i].mmap_data = mmap_data;
9518c2ecf20Sopenharmony_ci		args[i].dirent = dirent;
9528c2ecf20Sopenharmony_ci	}
9538c2ecf20Sopenharmony_ci	for (i = 0; i < m; i++) {
9548c2ecf20Sopenharmony_ci		args[i].num = num_per_thread + 1;
9558c2ecf20Sopenharmony_ci		args[i].start = i * args[i].num;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci	if (i != 0)
9588c2ecf20Sopenharmony_ci		base = args[i-1].start + args[i-1].num;
9598c2ecf20Sopenharmony_ci	for (j = i; j < thread_nr; j++) {
9608c2ecf20Sopenharmony_ci		args[j].num = num_per_thread;
9618c2ecf20Sopenharmony_ci		args[j].start = base + (j - i) * args[i].num;
9628c2ecf20Sopenharmony_ci	}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	for (i = 0; i < thread_nr; i++) {
9658c2ecf20Sopenharmony_ci		if (pthread_create(&synthesize_threads[i], NULL,
9668c2ecf20Sopenharmony_ci				   synthesize_threads_worker, &args[i]))
9678c2ecf20Sopenharmony_ci			goto out_join;
9688c2ecf20Sopenharmony_ci	}
9698c2ecf20Sopenharmony_ci	err = 0;
9708c2ecf20Sopenharmony_ciout_join:
9718c2ecf20Sopenharmony_ci	for (i = 0; i < thread_nr; i++)
9728c2ecf20Sopenharmony_ci		pthread_join(synthesize_threads[i], NULL);
9738c2ecf20Sopenharmony_ci	free(args);
9748c2ecf20Sopenharmony_cifree_threads:
9758c2ecf20Sopenharmony_ci	free(synthesize_threads);
9768c2ecf20Sopenharmony_cifree_dirent:
9778c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
9788c2ecf20Sopenharmony_ci		zfree(&dirent[i]);
9798c2ecf20Sopenharmony_ci	free(dirent);
9808c2ecf20Sopenharmony_ci
9818c2ecf20Sopenharmony_ci	return err;
9828c2ecf20Sopenharmony_ci}
9838c2ecf20Sopenharmony_ci
9848c2ecf20Sopenharmony_ciint __weak perf_event__synthesize_extra_kmaps(struct perf_tool *tool __maybe_unused,
9858c2ecf20Sopenharmony_ci					      perf_event__handler_t process __maybe_unused,
9868c2ecf20Sopenharmony_ci					      struct machine *machine __maybe_unused)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	return 0;
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_cistatic int __perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
9928c2ecf20Sopenharmony_ci						perf_event__handler_t process,
9938c2ecf20Sopenharmony_ci						struct machine *machine)
9948c2ecf20Sopenharmony_ci{
9958c2ecf20Sopenharmony_ci	size_t size;
9968c2ecf20Sopenharmony_ci	struct map *map = machine__kernel_map(machine);
9978c2ecf20Sopenharmony_ci	struct kmap *kmap;
9988c2ecf20Sopenharmony_ci	int err;
9998c2ecf20Sopenharmony_ci	union perf_event *event;
10008c2ecf20Sopenharmony_ci
10018c2ecf20Sopenharmony_ci	if (map == NULL)
10028c2ecf20Sopenharmony_ci		return -1;
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci	kmap = map__kmap(map);
10058c2ecf20Sopenharmony_ci	if (!kmap->ref_reloc_sym)
10068c2ecf20Sopenharmony_ci		return -1;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/*
10098c2ecf20Sopenharmony_ci	 * We should get this from /sys/kernel/sections/.text, but till that is
10108c2ecf20Sopenharmony_ci	 * available use this, and after it is use this as a fallback for older
10118c2ecf20Sopenharmony_ci	 * kernels.
10128c2ecf20Sopenharmony_ci	 */
10138c2ecf20Sopenharmony_ci	event = zalloc((sizeof(event->mmap) + machine->id_hdr_size));
10148c2ecf20Sopenharmony_ci	if (event == NULL) {
10158c2ecf20Sopenharmony_ci		pr_debug("Not enough memory synthesizing mmap event "
10168c2ecf20Sopenharmony_ci			 "for kernel modules\n");
10178c2ecf20Sopenharmony_ci		return -1;
10188c2ecf20Sopenharmony_ci	}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	if (machine__is_host(machine)) {
10218c2ecf20Sopenharmony_ci		/*
10228c2ecf20Sopenharmony_ci		 * kernel uses PERF_RECORD_MISC_USER for user space maps,
10238c2ecf20Sopenharmony_ci		 * see kernel/perf_event.c __perf_event_mmap
10248c2ecf20Sopenharmony_ci		 */
10258c2ecf20Sopenharmony_ci		event->header.misc = PERF_RECORD_MISC_KERNEL;
10268c2ecf20Sopenharmony_ci	} else {
10278c2ecf20Sopenharmony_ci		event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
10288c2ecf20Sopenharmony_ci	}
10298c2ecf20Sopenharmony_ci
10308c2ecf20Sopenharmony_ci	size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
10318c2ecf20Sopenharmony_ci			"%s%s", machine->mmap_name, kmap->ref_reloc_sym->name) + 1;
10328c2ecf20Sopenharmony_ci	size = PERF_ALIGN(size, sizeof(u64));
10338c2ecf20Sopenharmony_ci	event->mmap.header.type = PERF_RECORD_MMAP;
10348c2ecf20Sopenharmony_ci	event->mmap.header.size = (sizeof(event->mmap) -
10358c2ecf20Sopenharmony_ci			(sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
10368c2ecf20Sopenharmony_ci	event->mmap.pgoff = kmap->ref_reloc_sym->addr;
10378c2ecf20Sopenharmony_ci	event->mmap.start = map->start;
10388c2ecf20Sopenharmony_ci	event->mmap.len   = map->end - event->mmap.start;
10398c2ecf20Sopenharmony_ci	event->mmap.pid   = machine->pid;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	err = perf_tool__process_synth_event(tool, event, machine, process);
10428c2ecf20Sopenharmony_ci	free(event);
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	return err;
10458c2ecf20Sopenharmony_ci}
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ciint perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
10488c2ecf20Sopenharmony_ci				       perf_event__handler_t process,
10498c2ecf20Sopenharmony_ci				       struct machine *machine)
10508c2ecf20Sopenharmony_ci{
10518c2ecf20Sopenharmony_ci	int err;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	err = __perf_event__synthesize_kernel_mmap(tool, process, machine);
10548c2ecf20Sopenharmony_ci	if (err < 0)
10558c2ecf20Sopenharmony_ci		return err;
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_ci	return perf_event__synthesize_extra_kmaps(tool, process, machine);
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_ciint perf_event__synthesize_thread_map2(struct perf_tool *tool,
10618c2ecf20Sopenharmony_ci				      struct perf_thread_map *threads,
10628c2ecf20Sopenharmony_ci				      perf_event__handler_t process,
10638c2ecf20Sopenharmony_ci				      struct machine *machine)
10648c2ecf20Sopenharmony_ci{
10658c2ecf20Sopenharmony_ci	union perf_event *event;
10668c2ecf20Sopenharmony_ci	int i, err, size;
10678c2ecf20Sopenharmony_ci
10688c2ecf20Sopenharmony_ci	size  = sizeof(event->thread_map);
10698c2ecf20Sopenharmony_ci	size +=	threads->nr * sizeof(event->thread_map.entries[0]);
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	event = zalloc(size);
10728c2ecf20Sopenharmony_ci	if (!event)
10738c2ecf20Sopenharmony_ci		return -ENOMEM;
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_ci	event->header.type = PERF_RECORD_THREAD_MAP;
10768c2ecf20Sopenharmony_ci	event->header.size = size;
10778c2ecf20Sopenharmony_ci	event->thread_map.nr = threads->nr;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	for (i = 0; i < threads->nr; i++) {
10808c2ecf20Sopenharmony_ci		struct perf_record_thread_map_entry *entry = &event->thread_map.entries[i];
10818c2ecf20Sopenharmony_ci		char *comm = perf_thread_map__comm(threads, i);
10828c2ecf20Sopenharmony_ci
10838c2ecf20Sopenharmony_ci		if (!comm)
10848c2ecf20Sopenharmony_ci			comm = (char *) "";
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_ci		entry->pid = perf_thread_map__pid(threads, i);
10878c2ecf20Sopenharmony_ci		strncpy((char *) &entry->comm, comm, sizeof(entry->comm));
10888c2ecf20Sopenharmony_ci	}
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	err = process(tool, event, NULL, machine);
10918c2ecf20Sopenharmony_ci
10928c2ecf20Sopenharmony_ci	free(event);
10938c2ecf20Sopenharmony_ci	return err;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic void synthesize_cpus(struct cpu_map_entries *cpus,
10978c2ecf20Sopenharmony_ci			    struct perf_cpu_map *map)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	int i;
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ci	cpus->nr = map->nr;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	for (i = 0; i < map->nr; i++)
11048c2ecf20Sopenharmony_ci		cpus->cpu[i] = map->map[i];
11058c2ecf20Sopenharmony_ci}
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_cistatic void synthesize_mask(struct perf_record_record_cpu_map *mask,
11088c2ecf20Sopenharmony_ci			    struct perf_cpu_map *map, int max)
11098c2ecf20Sopenharmony_ci{
11108c2ecf20Sopenharmony_ci	int i;
11118c2ecf20Sopenharmony_ci
11128c2ecf20Sopenharmony_ci	mask->nr = BITS_TO_LONGS(max);
11138c2ecf20Sopenharmony_ci	mask->long_size = sizeof(long);
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	for (i = 0; i < map->nr; i++)
11168c2ecf20Sopenharmony_ci		set_bit(map->map[i], mask->mask);
11178c2ecf20Sopenharmony_ci}
11188c2ecf20Sopenharmony_ci
11198c2ecf20Sopenharmony_cistatic size_t cpus_size(struct perf_cpu_map *map)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	return sizeof(struct cpu_map_entries) + map->nr * sizeof(u16);
11228c2ecf20Sopenharmony_ci}
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cistatic size_t mask_size(struct perf_cpu_map *map, int *max)
11258c2ecf20Sopenharmony_ci{
11268c2ecf20Sopenharmony_ci	int i;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	*max = 0;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	for (i = 0; i < map->nr; i++) {
11318c2ecf20Sopenharmony_ci		/* bit possition of the cpu is + 1 */
11328c2ecf20Sopenharmony_ci		int bit = map->map[i] + 1;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci		if (bit > *max)
11358c2ecf20Sopenharmony_ci			*max = bit;
11368c2ecf20Sopenharmony_ci	}
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci	return sizeof(struct perf_record_record_cpu_map) + BITS_TO_LONGS(*max) * sizeof(long);
11398c2ecf20Sopenharmony_ci}
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_civoid *cpu_map_data__alloc(struct perf_cpu_map *map, size_t *size, u16 *type, int *max)
11428c2ecf20Sopenharmony_ci{
11438c2ecf20Sopenharmony_ci	size_t size_cpus, size_mask;
11448c2ecf20Sopenharmony_ci	bool is_dummy = perf_cpu_map__empty(map);
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	/*
11478c2ecf20Sopenharmony_ci	 * Both array and mask data have variable size based
11488c2ecf20Sopenharmony_ci	 * on the number of cpus and their actual values.
11498c2ecf20Sopenharmony_ci	 * The size of the 'struct perf_record_cpu_map_data' is:
11508c2ecf20Sopenharmony_ci	 *
11518c2ecf20Sopenharmony_ci	 *   array = size of 'struct cpu_map_entries' +
11528c2ecf20Sopenharmony_ci	 *           number of cpus * sizeof(u64)
11538c2ecf20Sopenharmony_ci	 *
11548c2ecf20Sopenharmony_ci	 *   mask  = size of 'struct perf_record_record_cpu_map' +
11558c2ecf20Sopenharmony_ci	 *           maximum cpu bit converted to size of longs
11568c2ecf20Sopenharmony_ci	 *
11578c2ecf20Sopenharmony_ci	 * and finaly + the size of 'struct perf_record_cpu_map_data'.
11588c2ecf20Sopenharmony_ci	 */
11598c2ecf20Sopenharmony_ci	size_cpus = cpus_size(map);
11608c2ecf20Sopenharmony_ci	size_mask = mask_size(map, max);
11618c2ecf20Sopenharmony_ci
11628c2ecf20Sopenharmony_ci	if (is_dummy || (size_cpus < size_mask)) {
11638c2ecf20Sopenharmony_ci		*size += size_cpus;
11648c2ecf20Sopenharmony_ci		*type  = PERF_CPU_MAP__CPUS;
11658c2ecf20Sopenharmony_ci	} else {
11668c2ecf20Sopenharmony_ci		*size += size_mask;
11678c2ecf20Sopenharmony_ci		*type  = PERF_CPU_MAP__MASK;
11688c2ecf20Sopenharmony_ci	}
11698c2ecf20Sopenharmony_ci
11708c2ecf20Sopenharmony_ci	*size += sizeof(struct perf_record_cpu_map_data);
11718c2ecf20Sopenharmony_ci	*size = PERF_ALIGN(*size, sizeof(u64));
11728c2ecf20Sopenharmony_ci	return zalloc(*size);
11738c2ecf20Sopenharmony_ci}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_civoid cpu_map_data__synthesize(struct perf_record_cpu_map_data *data, struct perf_cpu_map *map,
11768c2ecf20Sopenharmony_ci			      u16 type, int max)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	data->type = type;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	switch (type) {
11818c2ecf20Sopenharmony_ci	case PERF_CPU_MAP__CPUS:
11828c2ecf20Sopenharmony_ci		synthesize_cpus((struct cpu_map_entries *) data->data, map);
11838c2ecf20Sopenharmony_ci		break;
11848c2ecf20Sopenharmony_ci	case PERF_CPU_MAP__MASK:
11858c2ecf20Sopenharmony_ci		synthesize_mask((struct perf_record_record_cpu_map *)data->data, map, max);
11868c2ecf20Sopenharmony_ci	default:
11878c2ecf20Sopenharmony_ci		break;
11888c2ecf20Sopenharmony_ci	}
11898c2ecf20Sopenharmony_ci}
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_cistatic struct perf_record_cpu_map *cpu_map_event__new(struct perf_cpu_map *map)
11928c2ecf20Sopenharmony_ci{
11938c2ecf20Sopenharmony_ci	size_t size = sizeof(struct perf_record_cpu_map);
11948c2ecf20Sopenharmony_ci	struct perf_record_cpu_map *event;
11958c2ecf20Sopenharmony_ci	int max;
11968c2ecf20Sopenharmony_ci	u16 type;
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	event = cpu_map_data__alloc(map, &size, &type, &max);
11998c2ecf20Sopenharmony_ci	if (!event)
12008c2ecf20Sopenharmony_ci		return NULL;
12018c2ecf20Sopenharmony_ci
12028c2ecf20Sopenharmony_ci	event->header.type = PERF_RECORD_CPU_MAP;
12038c2ecf20Sopenharmony_ci	event->header.size = size;
12048c2ecf20Sopenharmony_ci	event->data.type   = type;
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	cpu_map_data__synthesize(&event->data, map, type, max);
12078c2ecf20Sopenharmony_ci	return event;
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ciint perf_event__synthesize_cpu_map(struct perf_tool *tool,
12118c2ecf20Sopenharmony_ci				   struct perf_cpu_map *map,
12128c2ecf20Sopenharmony_ci				   perf_event__handler_t process,
12138c2ecf20Sopenharmony_ci				   struct machine *machine)
12148c2ecf20Sopenharmony_ci{
12158c2ecf20Sopenharmony_ci	struct perf_record_cpu_map *event;
12168c2ecf20Sopenharmony_ci	int err;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci	event = cpu_map_event__new(map);
12198c2ecf20Sopenharmony_ci	if (!event)
12208c2ecf20Sopenharmony_ci		return -ENOMEM;
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_ci	err = process(tool, (union perf_event *) event, NULL, machine);
12238c2ecf20Sopenharmony_ci
12248c2ecf20Sopenharmony_ci	free(event);
12258c2ecf20Sopenharmony_ci	return err;
12268c2ecf20Sopenharmony_ci}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ciint perf_event__synthesize_stat_config(struct perf_tool *tool,
12298c2ecf20Sopenharmony_ci				       struct perf_stat_config *config,
12308c2ecf20Sopenharmony_ci				       perf_event__handler_t process,
12318c2ecf20Sopenharmony_ci				       struct machine *machine)
12328c2ecf20Sopenharmony_ci{
12338c2ecf20Sopenharmony_ci	struct perf_record_stat_config *event;
12348c2ecf20Sopenharmony_ci	int size, i = 0, err;
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci	size  = sizeof(*event);
12378c2ecf20Sopenharmony_ci	size += (PERF_STAT_CONFIG_TERM__MAX * sizeof(event->data[0]));
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	event = zalloc(size);
12408c2ecf20Sopenharmony_ci	if (!event)
12418c2ecf20Sopenharmony_ci		return -ENOMEM;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	event->header.type = PERF_RECORD_STAT_CONFIG;
12448c2ecf20Sopenharmony_ci	event->header.size = size;
12458c2ecf20Sopenharmony_ci	event->nr          = PERF_STAT_CONFIG_TERM__MAX;
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci#define ADD(__term, __val)					\
12488c2ecf20Sopenharmony_ci	event->data[i].tag = PERF_STAT_CONFIG_TERM__##__term;	\
12498c2ecf20Sopenharmony_ci	event->data[i].val = __val;				\
12508c2ecf20Sopenharmony_ci	i++;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	ADD(AGGR_MODE,	config->aggr_mode)
12538c2ecf20Sopenharmony_ci	ADD(INTERVAL,	config->interval)
12548c2ecf20Sopenharmony_ci	ADD(SCALE,	config->scale)
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	WARN_ONCE(i != PERF_STAT_CONFIG_TERM__MAX,
12578c2ecf20Sopenharmony_ci		  "stat config terms unbalanced\n");
12588c2ecf20Sopenharmony_ci#undef ADD
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	err = process(tool, (union perf_event *) event, NULL, machine);
12618c2ecf20Sopenharmony_ci
12628c2ecf20Sopenharmony_ci	free(event);
12638c2ecf20Sopenharmony_ci	return err;
12648c2ecf20Sopenharmony_ci}
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ciint perf_event__synthesize_stat(struct perf_tool *tool,
12678c2ecf20Sopenharmony_ci				u32 cpu, u32 thread, u64 id,
12688c2ecf20Sopenharmony_ci				struct perf_counts_values *count,
12698c2ecf20Sopenharmony_ci				perf_event__handler_t process,
12708c2ecf20Sopenharmony_ci				struct machine *machine)
12718c2ecf20Sopenharmony_ci{
12728c2ecf20Sopenharmony_ci	struct perf_record_stat event;
12738c2ecf20Sopenharmony_ci
12748c2ecf20Sopenharmony_ci	event.header.type = PERF_RECORD_STAT;
12758c2ecf20Sopenharmony_ci	event.header.size = sizeof(event);
12768c2ecf20Sopenharmony_ci	event.header.misc = 0;
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_ci	event.id        = id;
12798c2ecf20Sopenharmony_ci	event.cpu       = cpu;
12808c2ecf20Sopenharmony_ci	event.thread    = thread;
12818c2ecf20Sopenharmony_ci	event.val       = count->val;
12828c2ecf20Sopenharmony_ci	event.ena       = count->ena;
12838c2ecf20Sopenharmony_ci	event.run       = count->run;
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_ci	return process(tool, (union perf_event *) &event, NULL, machine);
12868c2ecf20Sopenharmony_ci}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ciint perf_event__synthesize_stat_round(struct perf_tool *tool,
12898c2ecf20Sopenharmony_ci				      u64 evtime, u64 type,
12908c2ecf20Sopenharmony_ci				      perf_event__handler_t process,
12918c2ecf20Sopenharmony_ci				      struct machine *machine)
12928c2ecf20Sopenharmony_ci{
12938c2ecf20Sopenharmony_ci	struct perf_record_stat_round event;
12948c2ecf20Sopenharmony_ci
12958c2ecf20Sopenharmony_ci	event.header.type = PERF_RECORD_STAT_ROUND;
12968c2ecf20Sopenharmony_ci	event.header.size = sizeof(event);
12978c2ecf20Sopenharmony_ci	event.header.misc = 0;
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci	event.time = evtime;
13008c2ecf20Sopenharmony_ci	event.type = type;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci	return process(tool, (union perf_event *) &event, NULL, machine);
13038c2ecf20Sopenharmony_ci}
13048c2ecf20Sopenharmony_ci
13058c2ecf20Sopenharmony_cisize_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format)
13068c2ecf20Sopenharmony_ci{
13078c2ecf20Sopenharmony_ci	size_t sz, result = sizeof(struct perf_record_sample);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_IDENTIFIER)
13108c2ecf20Sopenharmony_ci		result += sizeof(u64);
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_IP)
13138c2ecf20Sopenharmony_ci		result += sizeof(u64);
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_TID)
13168c2ecf20Sopenharmony_ci		result += sizeof(u64);
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_TIME)
13198c2ecf20Sopenharmony_ci		result += sizeof(u64);
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_ADDR)
13228c2ecf20Sopenharmony_ci		result += sizeof(u64);
13238c2ecf20Sopenharmony_ci
13248c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_ID)
13258c2ecf20Sopenharmony_ci		result += sizeof(u64);
13268c2ecf20Sopenharmony_ci
13278c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_STREAM_ID)
13288c2ecf20Sopenharmony_ci		result += sizeof(u64);
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_CPU)
13318c2ecf20Sopenharmony_ci		result += sizeof(u64);
13328c2ecf20Sopenharmony_ci
13338c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_PERIOD)
13348c2ecf20Sopenharmony_ci		result += sizeof(u64);
13358c2ecf20Sopenharmony_ci
13368c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_READ) {
13378c2ecf20Sopenharmony_ci		result += sizeof(u64);
13388c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED)
13398c2ecf20Sopenharmony_ci			result += sizeof(u64);
13408c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING)
13418c2ecf20Sopenharmony_ci			result += sizeof(u64);
13428c2ecf20Sopenharmony_ci		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
13438c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_GROUP) {
13448c2ecf20Sopenharmony_ci			sz = sample->read.group.nr *
13458c2ecf20Sopenharmony_ci			     sizeof(struct sample_read_value);
13468c2ecf20Sopenharmony_ci			result += sz;
13478c2ecf20Sopenharmony_ci		} else {
13488c2ecf20Sopenharmony_ci			result += sizeof(u64);
13498c2ecf20Sopenharmony_ci		}
13508c2ecf20Sopenharmony_ci	}
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_CALLCHAIN) {
13538c2ecf20Sopenharmony_ci		sz = (sample->callchain->nr + 1) * sizeof(u64);
13548c2ecf20Sopenharmony_ci		result += sz;
13558c2ecf20Sopenharmony_ci	}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_RAW) {
13588c2ecf20Sopenharmony_ci		result += sizeof(u32);
13598c2ecf20Sopenharmony_ci		result += sample->raw_size;
13608c2ecf20Sopenharmony_ci	}
13618c2ecf20Sopenharmony_ci
13628c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_BRANCH_STACK) {
13638c2ecf20Sopenharmony_ci		sz = sample->branch_stack->nr * sizeof(struct branch_entry);
13648c2ecf20Sopenharmony_ci		/* nr, hw_idx */
13658c2ecf20Sopenharmony_ci		sz += 2 * sizeof(u64);
13668c2ecf20Sopenharmony_ci		result += sz;
13678c2ecf20Sopenharmony_ci	}
13688c2ecf20Sopenharmony_ci
13698c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_REGS_USER) {
13708c2ecf20Sopenharmony_ci		if (sample->user_regs.abi) {
13718c2ecf20Sopenharmony_ci			result += sizeof(u64);
13728c2ecf20Sopenharmony_ci			sz = hweight64(sample->user_regs.mask) * sizeof(u64);
13738c2ecf20Sopenharmony_ci			result += sz;
13748c2ecf20Sopenharmony_ci		} else {
13758c2ecf20Sopenharmony_ci			result += sizeof(u64);
13768c2ecf20Sopenharmony_ci		}
13778c2ecf20Sopenharmony_ci	}
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_STACK_USER) {
13808c2ecf20Sopenharmony_ci		sz = sample->user_stack.size;
13818c2ecf20Sopenharmony_ci		result += sizeof(u64);
13828c2ecf20Sopenharmony_ci		if (sz) {
13838c2ecf20Sopenharmony_ci			result += sz;
13848c2ecf20Sopenharmony_ci			result += sizeof(u64);
13858c2ecf20Sopenharmony_ci		}
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_WEIGHT)
13898c2ecf20Sopenharmony_ci		result += sizeof(u64);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_DATA_SRC)
13928c2ecf20Sopenharmony_ci		result += sizeof(u64);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_TRANSACTION)
13958c2ecf20Sopenharmony_ci		result += sizeof(u64);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_REGS_INTR) {
13988c2ecf20Sopenharmony_ci		if (sample->intr_regs.abi) {
13998c2ecf20Sopenharmony_ci			result += sizeof(u64);
14008c2ecf20Sopenharmony_ci			sz = hweight64(sample->intr_regs.mask) * sizeof(u64);
14018c2ecf20Sopenharmony_ci			result += sz;
14028c2ecf20Sopenharmony_ci		} else {
14038c2ecf20Sopenharmony_ci			result += sizeof(u64);
14048c2ecf20Sopenharmony_ci		}
14058c2ecf20Sopenharmony_ci	}
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_PHYS_ADDR)
14088c2ecf20Sopenharmony_ci		result += sizeof(u64);
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_CGROUP)
14118c2ecf20Sopenharmony_ci		result += sizeof(u64);
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_AUX) {
14148c2ecf20Sopenharmony_ci		result += sizeof(u64);
14158c2ecf20Sopenharmony_ci		result += sample->aux_sample.size;
14168c2ecf20Sopenharmony_ci	}
14178c2ecf20Sopenharmony_ci
14188c2ecf20Sopenharmony_ci	return result;
14198c2ecf20Sopenharmony_ci}
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ciint perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
14228c2ecf20Sopenharmony_ci				  const struct perf_sample *sample)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	__u64 *array;
14258c2ecf20Sopenharmony_ci	size_t sz;
14268c2ecf20Sopenharmony_ci	/*
14278c2ecf20Sopenharmony_ci	 * used for cross-endian analysis. See git commit 65014ab3
14288c2ecf20Sopenharmony_ci	 * for why this goofiness is needed.
14298c2ecf20Sopenharmony_ci	 */
14308c2ecf20Sopenharmony_ci	union u64_swap u;
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_ci	array = event->sample.array;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_IDENTIFIER) {
14358c2ecf20Sopenharmony_ci		*array = sample->id;
14368c2ecf20Sopenharmony_ci		array++;
14378c2ecf20Sopenharmony_ci	}
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_IP) {
14408c2ecf20Sopenharmony_ci		*array = sample->ip;
14418c2ecf20Sopenharmony_ci		array++;
14428c2ecf20Sopenharmony_ci	}
14438c2ecf20Sopenharmony_ci
14448c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_TID) {
14458c2ecf20Sopenharmony_ci		u.val32[0] = sample->pid;
14468c2ecf20Sopenharmony_ci		u.val32[1] = sample->tid;
14478c2ecf20Sopenharmony_ci		*array = u.val64;
14488c2ecf20Sopenharmony_ci		array++;
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_TIME) {
14528c2ecf20Sopenharmony_ci		*array = sample->time;
14538c2ecf20Sopenharmony_ci		array++;
14548c2ecf20Sopenharmony_ci	}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_ADDR) {
14578c2ecf20Sopenharmony_ci		*array = sample->addr;
14588c2ecf20Sopenharmony_ci		array++;
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_ID) {
14628c2ecf20Sopenharmony_ci		*array = sample->id;
14638c2ecf20Sopenharmony_ci		array++;
14648c2ecf20Sopenharmony_ci	}
14658c2ecf20Sopenharmony_ci
14668c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_STREAM_ID) {
14678c2ecf20Sopenharmony_ci		*array = sample->stream_id;
14688c2ecf20Sopenharmony_ci		array++;
14698c2ecf20Sopenharmony_ci	}
14708c2ecf20Sopenharmony_ci
14718c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_CPU) {
14728c2ecf20Sopenharmony_ci		u.val32[0] = sample->cpu;
14738c2ecf20Sopenharmony_ci		u.val32[1] = 0;
14748c2ecf20Sopenharmony_ci		*array = u.val64;
14758c2ecf20Sopenharmony_ci		array++;
14768c2ecf20Sopenharmony_ci	}
14778c2ecf20Sopenharmony_ci
14788c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_PERIOD) {
14798c2ecf20Sopenharmony_ci		*array = sample->period;
14808c2ecf20Sopenharmony_ci		array++;
14818c2ecf20Sopenharmony_ci	}
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_READ) {
14848c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_GROUP)
14858c2ecf20Sopenharmony_ci			*array = sample->read.group.nr;
14868c2ecf20Sopenharmony_ci		else
14878c2ecf20Sopenharmony_ci			*array = sample->read.one.value;
14888c2ecf20Sopenharmony_ci		array++;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_TOTAL_TIME_ENABLED) {
14918c2ecf20Sopenharmony_ci			*array = sample->read.time_enabled;
14928c2ecf20Sopenharmony_ci			array++;
14938c2ecf20Sopenharmony_ci		}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_TOTAL_TIME_RUNNING) {
14968c2ecf20Sopenharmony_ci			*array = sample->read.time_running;
14978c2ecf20Sopenharmony_ci			array++;
14988c2ecf20Sopenharmony_ci		}
14998c2ecf20Sopenharmony_ci
15008c2ecf20Sopenharmony_ci		/* PERF_FORMAT_ID is forced for PERF_SAMPLE_READ */
15018c2ecf20Sopenharmony_ci		if (read_format & PERF_FORMAT_GROUP) {
15028c2ecf20Sopenharmony_ci			sz = sample->read.group.nr *
15038c2ecf20Sopenharmony_ci			     sizeof(struct sample_read_value);
15048c2ecf20Sopenharmony_ci			memcpy(array, sample->read.group.values, sz);
15058c2ecf20Sopenharmony_ci			array = (void *)array + sz;
15068c2ecf20Sopenharmony_ci		} else {
15078c2ecf20Sopenharmony_ci			*array = sample->read.one.id;
15088c2ecf20Sopenharmony_ci			array++;
15098c2ecf20Sopenharmony_ci		}
15108c2ecf20Sopenharmony_ci	}
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_CALLCHAIN) {
15138c2ecf20Sopenharmony_ci		sz = (sample->callchain->nr + 1) * sizeof(u64);
15148c2ecf20Sopenharmony_ci		memcpy(array, sample->callchain, sz);
15158c2ecf20Sopenharmony_ci		array = (void *)array + sz;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_RAW) {
15198c2ecf20Sopenharmony_ci		u.val32[0] = sample->raw_size;
15208c2ecf20Sopenharmony_ci		*array = u.val64;
15218c2ecf20Sopenharmony_ci		array = (void *)array + sizeof(u32);
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci		memcpy(array, sample->raw_data, sample->raw_size);
15248c2ecf20Sopenharmony_ci		array = (void *)array + sample->raw_size;
15258c2ecf20Sopenharmony_ci	}
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_BRANCH_STACK) {
15288c2ecf20Sopenharmony_ci		sz = sample->branch_stack->nr * sizeof(struct branch_entry);
15298c2ecf20Sopenharmony_ci		/* nr, hw_idx */
15308c2ecf20Sopenharmony_ci		sz += 2 * sizeof(u64);
15318c2ecf20Sopenharmony_ci		memcpy(array, sample->branch_stack, sz);
15328c2ecf20Sopenharmony_ci		array = (void *)array + sz;
15338c2ecf20Sopenharmony_ci	}
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_REGS_USER) {
15368c2ecf20Sopenharmony_ci		if (sample->user_regs.abi) {
15378c2ecf20Sopenharmony_ci			*array++ = sample->user_regs.abi;
15388c2ecf20Sopenharmony_ci			sz = hweight64(sample->user_regs.mask) * sizeof(u64);
15398c2ecf20Sopenharmony_ci			memcpy(array, sample->user_regs.regs, sz);
15408c2ecf20Sopenharmony_ci			array = (void *)array + sz;
15418c2ecf20Sopenharmony_ci		} else {
15428c2ecf20Sopenharmony_ci			*array++ = 0;
15438c2ecf20Sopenharmony_ci		}
15448c2ecf20Sopenharmony_ci	}
15458c2ecf20Sopenharmony_ci
15468c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_STACK_USER) {
15478c2ecf20Sopenharmony_ci		sz = sample->user_stack.size;
15488c2ecf20Sopenharmony_ci		*array++ = sz;
15498c2ecf20Sopenharmony_ci		if (sz) {
15508c2ecf20Sopenharmony_ci			memcpy(array, sample->user_stack.data, sz);
15518c2ecf20Sopenharmony_ci			array = (void *)array + sz;
15528c2ecf20Sopenharmony_ci			*array++ = sz;
15538c2ecf20Sopenharmony_ci		}
15548c2ecf20Sopenharmony_ci	}
15558c2ecf20Sopenharmony_ci
15568c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_WEIGHT) {
15578c2ecf20Sopenharmony_ci		*array = sample->weight;
15588c2ecf20Sopenharmony_ci		array++;
15598c2ecf20Sopenharmony_ci	}
15608c2ecf20Sopenharmony_ci
15618c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_DATA_SRC) {
15628c2ecf20Sopenharmony_ci		*array = sample->data_src;
15638c2ecf20Sopenharmony_ci		array++;
15648c2ecf20Sopenharmony_ci	}
15658c2ecf20Sopenharmony_ci
15668c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_TRANSACTION) {
15678c2ecf20Sopenharmony_ci		*array = sample->transaction;
15688c2ecf20Sopenharmony_ci		array++;
15698c2ecf20Sopenharmony_ci	}
15708c2ecf20Sopenharmony_ci
15718c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_REGS_INTR) {
15728c2ecf20Sopenharmony_ci		if (sample->intr_regs.abi) {
15738c2ecf20Sopenharmony_ci			*array++ = sample->intr_regs.abi;
15748c2ecf20Sopenharmony_ci			sz = hweight64(sample->intr_regs.mask) * sizeof(u64);
15758c2ecf20Sopenharmony_ci			memcpy(array, sample->intr_regs.regs, sz);
15768c2ecf20Sopenharmony_ci			array = (void *)array + sz;
15778c2ecf20Sopenharmony_ci		} else {
15788c2ecf20Sopenharmony_ci			*array++ = 0;
15798c2ecf20Sopenharmony_ci		}
15808c2ecf20Sopenharmony_ci	}
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_PHYS_ADDR) {
15838c2ecf20Sopenharmony_ci		*array = sample->phys_addr;
15848c2ecf20Sopenharmony_ci		array++;
15858c2ecf20Sopenharmony_ci	}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_CGROUP) {
15888c2ecf20Sopenharmony_ci		*array = sample->cgroup;
15898c2ecf20Sopenharmony_ci		array++;
15908c2ecf20Sopenharmony_ci	}
15918c2ecf20Sopenharmony_ci
15928c2ecf20Sopenharmony_ci	if (type & PERF_SAMPLE_AUX) {
15938c2ecf20Sopenharmony_ci		sz = sample->aux_sample.size;
15948c2ecf20Sopenharmony_ci		*array++ = sz;
15958c2ecf20Sopenharmony_ci		memcpy(array, sample->aux_sample.data, sz);
15968c2ecf20Sopenharmony_ci		array = (void *)array + sz;
15978c2ecf20Sopenharmony_ci	}
15988c2ecf20Sopenharmony_ci
15998c2ecf20Sopenharmony_ci	return 0;
16008c2ecf20Sopenharmony_ci}
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ciint perf_event__synthesize_id_index(struct perf_tool *tool, perf_event__handler_t process,
16038c2ecf20Sopenharmony_ci				    struct evlist *evlist, struct machine *machine)
16048c2ecf20Sopenharmony_ci{
16058c2ecf20Sopenharmony_ci	union perf_event *ev;
16068c2ecf20Sopenharmony_ci	struct evsel *evsel;
16078c2ecf20Sopenharmony_ci	size_t nr = 0, i = 0, sz, max_nr, n;
16088c2ecf20Sopenharmony_ci	int err;
16098c2ecf20Sopenharmony_ci
16108c2ecf20Sopenharmony_ci	pr_debug2("Synthesizing id index\n");
16118c2ecf20Sopenharmony_ci
16128c2ecf20Sopenharmony_ci	max_nr = (UINT16_MAX - sizeof(struct perf_record_id_index)) /
16138c2ecf20Sopenharmony_ci		 sizeof(struct id_index_entry);
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel)
16168c2ecf20Sopenharmony_ci		nr += evsel->core.ids;
16178c2ecf20Sopenharmony_ci
16188c2ecf20Sopenharmony_ci	n = nr > max_nr ? max_nr : nr;
16198c2ecf20Sopenharmony_ci	sz = sizeof(struct perf_record_id_index) + n * sizeof(struct id_index_entry);
16208c2ecf20Sopenharmony_ci	ev = zalloc(sz);
16218c2ecf20Sopenharmony_ci	if (!ev)
16228c2ecf20Sopenharmony_ci		return -ENOMEM;
16238c2ecf20Sopenharmony_ci
16248c2ecf20Sopenharmony_ci	ev->id_index.header.type = PERF_RECORD_ID_INDEX;
16258c2ecf20Sopenharmony_ci	ev->id_index.header.size = sz;
16268c2ecf20Sopenharmony_ci	ev->id_index.nr = n;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
16298c2ecf20Sopenharmony_ci		u32 j;
16308c2ecf20Sopenharmony_ci
16318c2ecf20Sopenharmony_ci		for (j = 0; j < evsel->core.ids; j++) {
16328c2ecf20Sopenharmony_ci			struct id_index_entry *e;
16338c2ecf20Sopenharmony_ci			struct perf_sample_id *sid;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci			if (i >= n) {
16368c2ecf20Sopenharmony_ci				err = process(tool, ev, NULL, machine);
16378c2ecf20Sopenharmony_ci				if (err)
16388c2ecf20Sopenharmony_ci					goto out_err;
16398c2ecf20Sopenharmony_ci				nr -= n;
16408c2ecf20Sopenharmony_ci				i = 0;
16418c2ecf20Sopenharmony_ci			}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci			e = &ev->id_index.entries[i++];
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci			e->id = evsel->core.id[j];
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci			sid = perf_evlist__id2sid(evlist, e->id);
16488c2ecf20Sopenharmony_ci			if (!sid) {
16498c2ecf20Sopenharmony_ci				free(ev);
16508c2ecf20Sopenharmony_ci				return -ENOENT;
16518c2ecf20Sopenharmony_ci			}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci			e->idx = sid->idx;
16548c2ecf20Sopenharmony_ci			e->cpu = sid->cpu;
16558c2ecf20Sopenharmony_ci			e->tid = sid->tid;
16568c2ecf20Sopenharmony_ci		}
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	sz = sizeof(struct perf_record_id_index) + nr * sizeof(struct id_index_entry);
16608c2ecf20Sopenharmony_ci	ev->id_index.header.size = sz;
16618c2ecf20Sopenharmony_ci	ev->id_index.nr = nr;
16628c2ecf20Sopenharmony_ci
16638c2ecf20Sopenharmony_ci	err = process(tool, ev, NULL, machine);
16648c2ecf20Sopenharmony_ciout_err:
16658c2ecf20Sopenharmony_ci	free(ev);
16668c2ecf20Sopenharmony_ci
16678c2ecf20Sopenharmony_ci	return err;
16688c2ecf20Sopenharmony_ci}
16698c2ecf20Sopenharmony_ci
16708c2ecf20Sopenharmony_ciint __machine__synthesize_threads(struct machine *machine, struct perf_tool *tool,
16718c2ecf20Sopenharmony_ci				  struct target *target, struct perf_thread_map *threads,
16728c2ecf20Sopenharmony_ci				  perf_event__handler_t process, bool data_mmap,
16738c2ecf20Sopenharmony_ci				  unsigned int nr_threads_synthesize)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	if (target__has_task(target))
16768c2ecf20Sopenharmony_ci		return perf_event__synthesize_thread_map(tool, threads, process, machine, data_mmap);
16778c2ecf20Sopenharmony_ci	else if (target__has_cpu(target))
16788c2ecf20Sopenharmony_ci		return perf_event__synthesize_threads(tool, process,
16798c2ecf20Sopenharmony_ci						      machine, data_mmap,
16808c2ecf20Sopenharmony_ci						      nr_threads_synthesize);
16818c2ecf20Sopenharmony_ci	/* command specified */
16828c2ecf20Sopenharmony_ci	return 0;
16838c2ecf20Sopenharmony_ci}
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ciint machine__synthesize_threads(struct machine *machine, struct target *target,
16868c2ecf20Sopenharmony_ci				struct perf_thread_map *threads, bool data_mmap,
16878c2ecf20Sopenharmony_ci				unsigned int nr_threads_synthesize)
16888c2ecf20Sopenharmony_ci{
16898c2ecf20Sopenharmony_ci	return __machine__synthesize_threads(machine, NULL, target, threads,
16908c2ecf20Sopenharmony_ci					     perf_event__process, data_mmap,
16918c2ecf20Sopenharmony_ci					     nr_threads_synthesize);
16928c2ecf20Sopenharmony_ci}
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_cistatic struct perf_record_event_update *event_update_event__new(size_t size, u64 type, u64 id)
16958c2ecf20Sopenharmony_ci{
16968c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev;
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	size += sizeof(*ev);
16998c2ecf20Sopenharmony_ci	size  = PERF_ALIGN(size, sizeof(u64));
17008c2ecf20Sopenharmony_ci
17018c2ecf20Sopenharmony_ci	ev = zalloc(size);
17028c2ecf20Sopenharmony_ci	if (ev) {
17038c2ecf20Sopenharmony_ci		ev->header.type = PERF_RECORD_EVENT_UPDATE;
17048c2ecf20Sopenharmony_ci		ev->header.size = (u16)size;
17058c2ecf20Sopenharmony_ci		ev->type	= type;
17068c2ecf20Sopenharmony_ci		ev->id		= id;
17078c2ecf20Sopenharmony_ci	}
17088c2ecf20Sopenharmony_ci	return ev;
17098c2ecf20Sopenharmony_ci}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_unit(struct perf_tool *tool, struct evsel *evsel,
17128c2ecf20Sopenharmony_ci					     perf_event__handler_t process)
17138c2ecf20Sopenharmony_ci{
17148c2ecf20Sopenharmony_ci	size_t size = strlen(evsel->unit);
17158c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev;
17168c2ecf20Sopenharmony_ci	int err;
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	ev = event_update_event__new(size + 1, PERF_EVENT_UPDATE__UNIT, evsel->core.id[0]);
17198c2ecf20Sopenharmony_ci	if (ev == NULL)
17208c2ecf20Sopenharmony_ci		return -ENOMEM;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	strlcpy(ev->data, evsel->unit, size + 1);
17238c2ecf20Sopenharmony_ci	err = process(tool, (union perf_event *)ev, NULL, NULL);
17248c2ecf20Sopenharmony_ci	free(ev);
17258c2ecf20Sopenharmony_ci	return err;
17268c2ecf20Sopenharmony_ci}
17278c2ecf20Sopenharmony_ci
17288c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_scale(struct perf_tool *tool, struct evsel *evsel,
17298c2ecf20Sopenharmony_ci					      perf_event__handler_t process)
17308c2ecf20Sopenharmony_ci{
17318c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev;
17328c2ecf20Sopenharmony_ci	struct perf_record_event_update_scale *ev_data;
17338c2ecf20Sopenharmony_ci	int err;
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	ev = event_update_event__new(sizeof(*ev_data), PERF_EVENT_UPDATE__SCALE, evsel->core.id[0]);
17368c2ecf20Sopenharmony_ci	if (ev == NULL)
17378c2ecf20Sopenharmony_ci		return -ENOMEM;
17388c2ecf20Sopenharmony_ci
17398c2ecf20Sopenharmony_ci	ev_data = (struct perf_record_event_update_scale *)ev->data;
17408c2ecf20Sopenharmony_ci	ev_data->scale = evsel->scale;
17418c2ecf20Sopenharmony_ci	err = process(tool, (union perf_event *)ev, NULL, NULL);
17428c2ecf20Sopenharmony_ci	free(ev);
17438c2ecf20Sopenharmony_ci	return err;
17448c2ecf20Sopenharmony_ci}
17458c2ecf20Sopenharmony_ci
17468c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_name(struct perf_tool *tool, struct evsel *evsel,
17478c2ecf20Sopenharmony_ci					     perf_event__handler_t process)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev;
17508c2ecf20Sopenharmony_ci	size_t len = strlen(evsel->name);
17518c2ecf20Sopenharmony_ci	int err;
17528c2ecf20Sopenharmony_ci
17538c2ecf20Sopenharmony_ci	ev = event_update_event__new(len + 1, PERF_EVENT_UPDATE__NAME, evsel->core.id[0]);
17548c2ecf20Sopenharmony_ci	if (ev == NULL)
17558c2ecf20Sopenharmony_ci		return -ENOMEM;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	strlcpy(ev->data, evsel->name, len + 1);
17588c2ecf20Sopenharmony_ci	err = process(tool, (union perf_event *)ev, NULL, NULL);
17598c2ecf20Sopenharmony_ci	free(ev);
17608c2ecf20Sopenharmony_ci	return err;
17618c2ecf20Sopenharmony_ci}
17628c2ecf20Sopenharmony_ci
17638c2ecf20Sopenharmony_ciint perf_event__synthesize_event_update_cpus(struct perf_tool *tool, struct evsel *evsel,
17648c2ecf20Sopenharmony_ci					     perf_event__handler_t process)
17658c2ecf20Sopenharmony_ci{
17668c2ecf20Sopenharmony_ci	size_t size = sizeof(struct perf_record_event_update);
17678c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev;
17688c2ecf20Sopenharmony_ci	int max, err;
17698c2ecf20Sopenharmony_ci	u16 type;
17708c2ecf20Sopenharmony_ci
17718c2ecf20Sopenharmony_ci	if (!evsel->core.own_cpus)
17728c2ecf20Sopenharmony_ci		return 0;
17738c2ecf20Sopenharmony_ci
17748c2ecf20Sopenharmony_ci	ev = cpu_map_data__alloc(evsel->core.own_cpus, &size, &type, &max);
17758c2ecf20Sopenharmony_ci	if (!ev)
17768c2ecf20Sopenharmony_ci		return -ENOMEM;
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci	ev->header.type = PERF_RECORD_EVENT_UPDATE;
17798c2ecf20Sopenharmony_ci	ev->header.size = (u16)size;
17808c2ecf20Sopenharmony_ci	ev->type	= PERF_EVENT_UPDATE__CPUS;
17818c2ecf20Sopenharmony_ci	ev->id		= evsel->core.id[0];
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci	cpu_map_data__synthesize((struct perf_record_cpu_map_data *)ev->data,
17848c2ecf20Sopenharmony_ci				 evsel->core.own_cpus, type, max);
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci	err = process(tool, (union perf_event *)ev, NULL, NULL);
17878c2ecf20Sopenharmony_ci	free(ev);
17888c2ecf20Sopenharmony_ci	return err;
17898c2ecf20Sopenharmony_ci}
17908c2ecf20Sopenharmony_ci
17918c2ecf20Sopenharmony_ciint perf_event__synthesize_attrs(struct perf_tool *tool, struct evlist *evlist,
17928c2ecf20Sopenharmony_ci				 perf_event__handler_t process)
17938c2ecf20Sopenharmony_ci{
17948c2ecf20Sopenharmony_ci	struct evsel *evsel;
17958c2ecf20Sopenharmony_ci	int err = 0;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
17988c2ecf20Sopenharmony_ci		err = perf_event__synthesize_attr(tool, &evsel->core.attr, evsel->core.ids,
17998c2ecf20Sopenharmony_ci						  evsel->core.id, process);
18008c2ecf20Sopenharmony_ci		if (err) {
18018c2ecf20Sopenharmony_ci			pr_debug("failed to create perf header attribute\n");
18028c2ecf20Sopenharmony_ci			return err;
18038c2ecf20Sopenharmony_ci		}
18048c2ecf20Sopenharmony_ci	}
18058c2ecf20Sopenharmony_ci
18068c2ecf20Sopenharmony_ci	return err;
18078c2ecf20Sopenharmony_ci}
18088c2ecf20Sopenharmony_ci
18098c2ecf20Sopenharmony_cistatic bool has_unit(struct evsel *evsel)
18108c2ecf20Sopenharmony_ci{
18118c2ecf20Sopenharmony_ci	return evsel->unit && *evsel->unit;
18128c2ecf20Sopenharmony_ci}
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_cistatic bool has_scale(struct evsel *evsel)
18158c2ecf20Sopenharmony_ci{
18168c2ecf20Sopenharmony_ci	return evsel->scale != 1;
18178c2ecf20Sopenharmony_ci}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ciint perf_event__synthesize_extra_attr(struct perf_tool *tool, struct evlist *evsel_list,
18208c2ecf20Sopenharmony_ci				      perf_event__handler_t process, bool is_pipe)
18218c2ecf20Sopenharmony_ci{
18228c2ecf20Sopenharmony_ci	struct evsel *evsel;
18238c2ecf20Sopenharmony_ci	int err;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ci	/*
18268c2ecf20Sopenharmony_ci	 * Synthesize other events stuff not carried within
18278c2ecf20Sopenharmony_ci	 * attr event - unit, scale, name
18288c2ecf20Sopenharmony_ci	 */
18298c2ecf20Sopenharmony_ci	evlist__for_each_entry(evsel_list, evsel) {
18308c2ecf20Sopenharmony_ci		if (!evsel->supported)
18318c2ecf20Sopenharmony_ci			continue;
18328c2ecf20Sopenharmony_ci
18338c2ecf20Sopenharmony_ci		/*
18348c2ecf20Sopenharmony_ci		 * Synthesize unit and scale only if it's defined.
18358c2ecf20Sopenharmony_ci		 */
18368c2ecf20Sopenharmony_ci		if (has_unit(evsel)) {
18378c2ecf20Sopenharmony_ci			err = perf_event__synthesize_event_update_unit(tool, evsel, process);
18388c2ecf20Sopenharmony_ci			if (err < 0) {
18398c2ecf20Sopenharmony_ci				pr_err("Couldn't synthesize evsel unit.\n");
18408c2ecf20Sopenharmony_ci				return err;
18418c2ecf20Sopenharmony_ci			}
18428c2ecf20Sopenharmony_ci		}
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci		if (has_scale(evsel)) {
18458c2ecf20Sopenharmony_ci			err = perf_event__synthesize_event_update_scale(tool, evsel, process);
18468c2ecf20Sopenharmony_ci			if (err < 0) {
18478c2ecf20Sopenharmony_ci				pr_err("Couldn't synthesize evsel evsel.\n");
18488c2ecf20Sopenharmony_ci				return err;
18498c2ecf20Sopenharmony_ci			}
18508c2ecf20Sopenharmony_ci		}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		if (evsel->core.own_cpus) {
18538c2ecf20Sopenharmony_ci			err = perf_event__synthesize_event_update_cpus(tool, evsel, process);
18548c2ecf20Sopenharmony_ci			if (err < 0) {
18558c2ecf20Sopenharmony_ci				pr_err("Couldn't synthesize evsel cpus.\n");
18568c2ecf20Sopenharmony_ci				return err;
18578c2ecf20Sopenharmony_ci			}
18588c2ecf20Sopenharmony_ci		}
18598c2ecf20Sopenharmony_ci
18608c2ecf20Sopenharmony_ci		/*
18618c2ecf20Sopenharmony_ci		 * Name is needed only for pipe output,
18628c2ecf20Sopenharmony_ci		 * perf.data carries event names.
18638c2ecf20Sopenharmony_ci		 */
18648c2ecf20Sopenharmony_ci		if (is_pipe) {
18658c2ecf20Sopenharmony_ci			err = perf_event__synthesize_event_update_name(tool, evsel, process);
18668c2ecf20Sopenharmony_ci			if (err < 0) {
18678c2ecf20Sopenharmony_ci				pr_err("Couldn't synthesize evsel name.\n");
18688c2ecf20Sopenharmony_ci				return err;
18698c2ecf20Sopenharmony_ci			}
18708c2ecf20Sopenharmony_ci		}
18718c2ecf20Sopenharmony_ci	}
18728c2ecf20Sopenharmony_ci	return 0;
18738c2ecf20Sopenharmony_ci}
18748c2ecf20Sopenharmony_ci
18758c2ecf20Sopenharmony_ciint perf_event__synthesize_attr(struct perf_tool *tool, struct perf_event_attr *attr,
18768c2ecf20Sopenharmony_ci				u32 ids, u64 *id, perf_event__handler_t process)
18778c2ecf20Sopenharmony_ci{
18788c2ecf20Sopenharmony_ci	union perf_event *ev;
18798c2ecf20Sopenharmony_ci	size_t size;
18808c2ecf20Sopenharmony_ci	int err;
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci	size = sizeof(struct perf_event_attr);
18838c2ecf20Sopenharmony_ci	size = PERF_ALIGN(size, sizeof(u64));
18848c2ecf20Sopenharmony_ci	size += sizeof(struct perf_event_header);
18858c2ecf20Sopenharmony_ci	size += ids * sizeof(u64);
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_ci	ev = zalloc(size);
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	if (ev == NULL)
18908c2ecf20Sopenharmony_ci		return -ENOMEM;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	ev->attr.attr = *attr;
18938c2ecf20Sopenharmony_ci	memcpy(ev->attr.id, id, ids * sizeof(u64));
18948c2ecf20Sopenharmony_ci
18958c2ecf20Sopenharmony_ci	ev->attr.header.type = PERF_RECORD_HEADER_ATTR;
18968c2ecf20Sopenharmony_ci	ev->attr.header.size = (u16)size;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	if (ev->attr.header.size == size)
18998c2ecf20Sopenharmony_ci		err = process(tool, ev, NULL, NULL);
19008c2ecf20Sopenharmony_ci	else
19018c2ecf20Sopenharmony_ci		err = -E2BIG;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	free(ev);
19048c2ecf20Sopenharmony_ci
19058c2ecf20Sopenharmony_ci	return err;
19068c2ecf20Sopenharmony_ci}
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ciint perf_event__synthesize_tracing_data(struct perf_tool *tool, int fd, struct evlist *evlist,
19098c2ecf20Sopenharmony_ci					perf_event__handler_t process)
19108c2ecf20Sopenharmony_ci{
19118c2ecf20Sopenharmony_ci	union perf_event ev;
19128c2ecf20Sopenharmony_ci	struct tracing_data *tdata;
19138c2ecf20Sopenharmony_ci	ssize_t size = 0, aligned_size = 0, padding;
19148c2ecf20Sopenharmony_ci	struct feat_fd ff;
19158c2ecf20Sopenharmony_ci
19168c2ecf20Sopenharmony_ci	/*
19178c2ecf20Sopenharmony_ci	 * We are going to store the size of the data followed
19188c2ecf20Sopenharmony_ci	 * by the data contents. Since the fd descriptor is a pipe,
19198c2ecf20Sopenharmony_ci	 * we cannot seek back to store the size of the data once
19208c2ecf20Sopenharmony_ci	 * we know it. Instead we:
19218c2ecf20Sopenharmony_ci	 *
19228c2ecf20Sopenharmony_ci	 * - write the tracing data to the temp file
19238c2ecf20Sopenharmony_ci	 * - get/write the data size to pipe
19248c2ecf20Sopenharmony_ci	 * - write the tracing data from the temp file
19258c2ecf20Sopenharmony_ci	 *   to the pipe
19268c2ecf20Sopenharmony_ci	 */
19278c2ecf20Sopenharmony_ci	tdata = tracing_data_get(&evlist->core.entries, fd, true);
19288c2ecf20Sopenharmony_ci	if (!tdata)
19298c2ecf20Sopenharmony_ci		return -1;
19308c2ecf20Sopenharmony_ci
19318c2ecf20Sopenharmony_ci	memset(&ev, 0, sizeof(ev));
19328c2ecf20Sopenharmony_ci
19338c2ecf20Sopenharmony_ci	ev.tracing_data.header.type = PERF_RECORD_HEADER_TRACING_DATA;
19348c2ecf20Sopenharmony_ci	size = tdata->size;
19358c2ecf20Sopenharmony_ci	aligned_size = PERF_ALIGN(size, sizeof(u64));
19368c2ecf20Sopenharmony_ci	padding = aligned_size - size;
19378c2ecf20Sopenharmony_ci	ev.tracing_data.header.size = sizeof(ev.tracing_data);
19388c2ecf20Sopenharmony_ci	ev.tracing_data.size = aligned_size;
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	process(tool, &ev, NULL, NULL);
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci	/*
19438c2ecf20Sopenharmony_ci	 * The put function will copy all the tracing data
19448c2ecf20Sopenharmony_ci	 * stored in temp file to the pipe.
19458c2ecf20Sopenharmony_ci	 */
19468c2ecf20Sopenharmony_ci	tracing_data_put(tdata);
19478c2ecf20Sopenharmony_ci
19488c2ecf20Sopenharmony_ci	ff = (struct feat_fd){ .fd = fd };
19498c2ecf20Sopenharmony_ci	if (write_padded(&ff, NULL, 0, padding))
19508c2ecf20Sopenharmony_ci		return -1;
19518c2ecf20Sopenharmony_ci
19528c2ecf20Sopenharmony_ci	return aligned_size;
19538c2ecf20Sopenharmony_ci}
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ciint perf_event__synthesize_build_id(struct perf_tool *tool, struct dso *pos, u16 misc,
19568c2ecf20Sopenharmony_ci				    perf_event__handler_t process, struct machine *machine)
19578c2ecf20Sopenharmony_ci{
19588c2ecf20Sopenharmony_ci	union perf_event ev;
19598c2ecf20Sopenharmony_ci	size_t len;
19608c2ecf20Sopenharmony_ci
19618c2ecf20Sopenharmony_ci	if (!pos->hit)
19628c2ecf20Sopenharmony_ci		return 0;
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci	memset(&ev, 0, sizeof(ev));
19658c2ecf20Sopenharmony_ci
19668c2ecf20Sopenharmony_ci	len = pos->long_name_len + 1;
19678c2ecf20Sopenharmony_ci	len = PERF_ALIGN(len, NAME_ALIGN);
19688c2ecf20Sopenharmony_ci	memcpy(&ev.build_id.build_id, pos->bid.data, sizeof(pos->bid.data));
19698c2ecf20Sopenharmony_ci	ev.build_id.header.type = PERF_RECORD_HEADER_BUILD_ID;
19708c2ecf20Sopenharmony_ci	ev.build_id.header.misc = misc;
19718c2ecf20Sopenharmony_ci	ev.build_id.pid = machine->pid;
19728c2ecf20Sopenharmony_ci	ev.build_id.header.size = sizeof(ev.build_id) + len;
19738c2ecf20Sopenharmony_ci	memcpy(&ev.build_id.filename, pos->long_name, pos->long_name_len);
19748c2ecf20Sopenharmony_ci
19758c2ecf20Sopenharmony_ci	return process(tool, &ev, NULL, machine);
19768c2ecf20Sopenharmony_ci}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ciint perf_event__synthesize_stat_events(struct perf_stat_config *config, struct perf_tool *tool,
19798c2ecf20Sopenharmony_ci				       struct evlist *evlist, perf_event__handler_t process, bool attrs)
19808c2ecf20Sopenharmony_ci{
19818c2ecf20Sopenharmony_ci	int err;
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	if (attrs) {
19848c2ecf20Sopenharmony_ci		err = perf_event__synthesize_attrs(tool, evlist, process);
19858c2ecf20Sopenharmony_ci		if (err < 0) {
19868c2ecf20Sopenharmony_ci			pr_err("Couldn't synthesize attrs.\n");
19878c2ecf20Sopenharmony_ci			return err;
19888c2ecf20Sopenharmony_ci		}
19898c2ecf20Sopenharmony_ci	}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci	err = perf_event__synthesize_extra_attr(tool, evlist, process, attrs);
19928c2ecf20Sopenharmony_ci	err = perf_event__synthesize_thread_map2(tool, evlist->core.threads, process, NULL);
19938c2ecf20Sopenharmony_ci	if (err < 0) {
19948c2ecf20Sopenharmony_ci		pr_err("Couldn't synthesize thread map.\n");
19958c2ecf20Sopenharmony_ci		return err;
19968c2ecf20Sopenharmony_ci	}
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	err = perf_event__synthesize_cpu_map(tool, evlist->core.cpus, process, NULL);
19998c2ecf20Sopenharmony_ci	if (err < 0) {
20008c2ecf20Sopenharmony_ci		pr_err("Couldn't synthesize thread map.\n");
20018c2ecf20Sopenharmony_ci		return err;
20028c2ecf20Sopenharmony_ci	}
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci	err = perf_event__synthesize_stat_config(tool, config, process, NULL);
20058c2ecf20Sopenharmony_ci	if (err < 0) {
20068c2ecf20Sopenharmony_ci		pr_err("Couldn't synthesize config.\n");
20078c2ecf20Sopenharmony_ci		return err;
20088c2ecf20Sopenharmony_ci	}
20098c2ecf20Sopenharmony_ci
20108c2ecf20Sopenharmony_ci	return 0;
20118c2ecf20Sopenharmony_ci}
20128c2ecf20Sopenharmony_ci
20138c2ecf20Sopenharmony_ciextern const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE];
20148c2ecf20Sopenharmony_ci
20158c2ecf20Sopenharmony_ciint perf_event__synthesize_features(struct perf_tool *tool, struct perf_session *session,
20168c2ecf20Sopenharmony_ci				    struct evlist *evlist, perf_event__handler_t process)
20178c2ecf20Sopenharmony_ci{
20188c2ecf20Sopenharmony_ci	struct perf_header *header = &session->header;
20198c2ecf20Sopenharmony_ci	struct perf_record_header_feature *fe;
20208c2ecf20Sopenharmony_ci	struct feat_fd ff;
20218c2ecf20Sopenharmony_ci	size_t sz, sz_hdr;
20228c2ecf20Sopenharmony_ci	int feat, ret;
20238c2ecf20Sopenharmony_ci
20248c2ecf20Sopenharmony_ci	sz_hdr = sizeof(fe->header);
20258c2ecf20Sopenharmony_ci	sz = sizeof(union perf_event);
20268c2ecf20Sopenharmony_ci	/* get a nice alignment */
20278c2ecf20Sopenharmony_ci	sz = PERF_ALIGN(sz, page_size);
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	memset(&ff, 0, sizeof(ff));
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	ff.buf = malloc(sz);
20328c2ecf20Sopenharmony_ci	if (!ff.buf)
20338c2ecf20Sopenharmony_ci		return -ENOMEM;
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	ff.size = sz - sz_hdr;
20368c2ecf20Sopenharmony_ci	ff.ph = &session->header;
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_ci	for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
20398c2ecf20Sopenharmony_ci		if (!feat_ops[feat].synthesize) {
20408c2ecf20Sopenharmony_ci			pr_debug("No record header feature for header :%d\n", feat);
20418c2ecf20Sopenharmony_ci			continue;
20428c2ecf20Sopenharmony_ci		}
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci		ff.offset = sizeof(*fe);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci		ret = feat_ops[feat].write(&ff, evlist);
20478c2ecf20Sopenharmony_ci		if (ret || ff.offset <= (ssize_t)sizeof(*fe)) {
20488c2ecf20Sopenharmony_ci			pr_debug("Error writing feature\n");
20498c2ecf20Sopenharmony_ci			continue;
20508c2ecf20Sopenharmony_ci		}
20518c2ecf20Sopenharmony_ci		/* ff.buf may have changed due to realloc in do_write() */
20528c2ecf20Sopenharmony_ci		fe = ff.buf;
20538c2ecf20Sopenharmony_ci		memset(fe, 0, sizeof(*fe));
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci		fe->feat_id = feat;
20568c2ecf20Sopenharmony_ci		fe->header.type = PERF_RECORD_HEADER_FEATURE;
20578c2ecf20Sopenharmony_ci		fe->header.size = ff.offset;
20588c2ecf20Sopenharmony_ci
20598c2ecf20Sopenharmony_ci		ret = process(tool, ff.buf, NULL, NULL);
20608c2ecf20Sopenharmony_ci		if (ret) {
20618c2ecf20Sopenharmony_ci			free(ff.buf);
20628c2ecf20Sopenharmony_ci			return ret;
20638c2ecf20Sopenharmony_ci		}
20648c2ecf20Sopenharmony_ci	}
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	/* Send HEADER_LAST_FEATURE mark. */
20678c2ecf20Sopenharmony_ci	fe = ff.buf;
20688c2ecf20Sopenharmony_ci	fe->feat_id     = HEADER_LAST_FEATURE;
20698c2ecf20Sopenharmony_ci	fe->header.type = PERF_RECORD_HEADER_FEATURE;
20708c2ecf20Sopenharmony_ci	fe->header.size = sizeof(*fe);
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	ret = process(tool, ff.buf, NULL, NULL);
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci	free(ff.buf);
20758c2ecf20Sopenharmony_ci	return ret;
20768c2ecf20Sopenharmony_ci}
2077