18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <errno.h>
38c2ecf20Sopenharmony_ci#include <inttypes.h>
48c2ecf20Sopenharmony_ci#include "string2.h"
58c2ecf20Sopenharmony_ci#include <sys/param.h>
68c2ecf20Sopenharmony_ci#include <sys/types.h>
78c2ecf20Sopenharmony_ci#include <byteswap.h>
88c2ecf20Sopenharmony_ci#include <unistd.h>
98c2ecf20Sopenharmony_ci#include <stdio.h>
108c2ecf20Sopenharmony_ci#include <stdlib.h>
118c2ecf20Sopenharmony_ci#include <linux/compiler.h>
128c2ecf20Sopenharmony_ci#include <linux/list.h>
138c2ecf20Sopenharmony_ci#include <linux/kernel.h>
148c2ecf20Sopenharmony_ci#include <linux/bitops.h>
158c2ecf20Sopenharmony_ci#include <linux/string.h>
168c2ecf20Sopenharmony_ci#include <linux/stringify.h>
178c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
188c2ecf20Sopenharmony_ci#include <sys/stat.h>
198c2ecf20Sopenharmony_ci#include <sys/utsname.h>
208c2ecf20Sopenharmony_ci#include <linux/time64.h>
218c2ecf20Sopenharmony_ci#include <dirent.h>
228c2ecf20Sopenharmony_ci#include <bpf/libbpf.h>
238c2ecf20Sopenharmony_ci#include <perf/cpumap.h>
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci#include "dso.h"
268c2ecf20Sopenharmony_ci#include "evlist.h"
278c2ecf20Sopenharmony_ci#include "evsel.h"
288c2ecf20Sopenharmony_ci#include "util/evsel_fprintf.h"
298c2ecf20Sopenharmony_ci#include "header.h"
308c2ecf20Sopenharmony_ci#include "memswap.h"
318c2ecf20Sopenharmony_ci#include "trace-event.h"
328c2ecf20Sopenharmony_ci#include "session.h"
338c2ecf20Sopenharmony_ci#include "symbol.h"
348c2ecf20Sopenharmony_ci#include "debug.h"
358c2ecf20Sopenharmony_ci#include "cpumap.h"
368c2ecf20Sopenharmony_ci#include "pmu.h"
378c2ecf20Sopenharmony_ci#include "vdso.h"
388c2ecf20Sopenharmony_ci#include "strbuf.h"
398c2ecf20Sopenharmony_ci#include "build-id.h"
408c2ecf20Sopenharmony_ci#include "data.h"
418c2ecf20Sopenharmony_ci#include <api/fs/fs.h>
428c2ecf20Sopenharmony_ci#include "asm/bug.h"
438c2ecf20Sopenharmony_ci#include "tool.h"
448c2ecf20Sopenharmony_ci#include "time-utils.h"
458c2ecf20Sopenharmony_ci#include "units.h"
468c2ecf20Sopenharmony_ci#include "util/util.h" // perf_exe()
478c2ecf20Sopenharmony_ci#include "cputopo.h"
488c2ecf20Sopenharmony_ci#include "bpf-event.h"
498c2ecf20Sopenharmony_ci#include "clockid.h"
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#include <linux/ctype.h>
528c2ecf20Sopenharmony_ci#include <internal/lib.h>
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/*
558c2ecf20Sopenharmony_ci * magic2 = "PERFILE2"
568c2ecf20Sopenharmony_ci * must be a numerical value to let the endianness
578c2ecf20Sopenharmony_ci * determine the memory layout. That way we are able
588c2ecf20Sopenharmony_ci * to detect endianness when reading the perf.data file
598c2ecf20Sopenharmony_ci * back.
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * we check for legacy (PERFFILE) format.
628c2ecf20Sopenharmony_ci */
638c2ecf20Sopenharmony_cistatic const char *__perf_magic1 = "PERFFILE";
648c2ecf20Sopenharmony_cistatic const u64 __perf_magic2    = 0x32454c4946524550ULL;
658c2ecf20Sopenharmony_cistatic const u64 __perf_magic2_sw = 0x50455246494c4532ULL;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci#define PERF_MAGIC	__perf_magic2
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ciconst char perf_version_string[] = PERF_VERSION;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistruct perf_file_attr {
728c2ecf20Sopenharmony_ci	struct perf_event_attr	attr;
738c2ecf20Sopenharmony_ci	struct perf_file_section	ids;
748c2ecf20Sopenharmony_ci};
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_civoid perf_header__set_feat(struct perf_header *header, int feat)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	set_bit(feat, header->adds_features);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_civoid perf_header__clear_feat(struct perf_header *header, int feat)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	clear_bit(feat, header->adds_features);
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_cibool perf_header__has_feat(const struct perf_header *header, int feat)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	return test_bit(feat, header->adds_features);
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_cistatic int __do_write_fd(struct feat_fd *ff, const void *buf, size_t size)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	ssize_t ret = writen(ff->fd, buf, size);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	if (ret != (ssize_t)size)
968c2ecf20Sopenharmony_ci		return ret < 0 ? (int)ret : -1;
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int __do_write_buf(struct feat_fd *ff,  const void *buf, size_t size)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	/* struct perf_event_header::size is u16 */
1038c2ecf20Sopenharmony_ci	const size_t max_size = 0xffff - sizeof(struct perf_event_header);
1048c2ecf20Sopenharmony_ci	size_t new_size = ff->size;
1058c2ecf20Sopenharmony_ci	void *addr;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	if (size + ff->offset > max_size)
1088c2ecf20Sopenharmony_ci		return -E2BIG;
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	while (size > (new_size - ff->offset))
1118c2ecf20Sopenharmony_ci		new_size <<= 1;
1128c2ecf20Sopenharmony_ci	new_size = min(max_size, new_size);
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	if (ff->size < new_size) {
1158c2ecf20Sopenharmony_ci		addr = realloc(ff->buf, new_size);
1168c2ecf20Sopenharmony_ci		if (!addr)
1178c2ecf20Sopenharmony_ci			return -ENOMEM;
1188c2ecf20Sopenharmony_ci		ff->buf = addr;
1198c2ecf20Sopenharmony_ci		ff->size = new_size;
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	memcpy(ff->buf + ff->offset, buf, size);
1238c2ecf20Sopenharmony_ci	ff->offset += size;
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	return 0;
1268c2ecf20Sopenharmony_ci}
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */
1298c2ecf20Sopenharmony_ciint do_write(struct feat_fd *ff, const void *buf, size_t size)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	if (!ff->buf)
1328c2ecf20Sopenharmony_ci		return __do_write_fd(ff, buf, size);
1338c2ecf20Sopenharmony_ci	return __do_write_buf(ff, buf, size);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */
1378c2ecf20Sopenharmony_cistatic int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size)
1388c2ecf20Sopenharmony_ci{
1398c2ecf20Sopenharmony_ci	u64 *p = (u64 *) set;
1408c2ecf20Sopenharmony_ci	int i, ret;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	ret = do_write(ff, &size, sizeof(size));
1438c2ecf20Sopenharmony_ci	if (ret < 0)
1448c2ecf20Sopenharmony_ci		return ret;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
1478c2ecf20Sopenharmony_ci		ret = do_write(ff, p + i, sizeof(*p));
1488c2ecf20Sopenharmony_ci		if (ret < 0)
1498c2ecf20Sopenharmony_ci			return ret;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	return 0;
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */
1568c2ecf20Sopenharmony_ciint write_padded(struct feat_fd *ff, const void *bf,
1578c2ecf20Sopenharmony_ci		 size_t count, size_t count_aligned)
1588c2ecf20Sopenharmony_ci{
1598c2ecf20Sopenharmony_ci	static const char zero_buf[NAME_ALIGN];
1608c2ecf20Sopenharmony_ci	int err = do_write(ff, bf, count);
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (!err)
1638c2ecf20Sopenharmony_ci		err = do_write(ff, zero_buf, count_aligned - count);
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	return err;
1668c2ecf20Sopenharmony_ci}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci#define string_size(str)						\
1698c2ecf20Sopenharmony_ci	(PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32))
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */
1728c2ecf20Sopenharmony_cistatic int do_write_string(struct feat_fd *ff, const char *str)
1738c2ecf20Sopenharmony_ci{
1748c2ecf20Sopenharmony_ci	u32 len, olen;
1758c2ecf20Sopenharmony_ci	int ret;
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	olen = strlen(str) + 1;
1788c2ecf20Sopenharmony_ci	len = PERF_ALIGN(olen, NAME_ALIGN);
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci	/* write len, incl. \0 */
1818c2ecf20Sopenharmony_ci	ret = do_write(ff, &len, sizeof(len));
1828c2ecf20Sopenharmony_ci	if (ret < 0)
1838c2ecf20Sopenharmony_ci		return ret;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	return write_padded(ff, str, olen, len);
1868c2ecf20Sopenharmony_ci}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_cistatic int __do_read_fd(struct feat_fd *ff, void *addr, ssize_t size)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	ssize_t ret = readn(ff->fd, addr, size);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	if (ret != size)
1938c2ecf20Sopenharmony_ci		return ret < 0 ? (int)ret : -1;
1948c2ecf20Sopenharmony_ci	return 0;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	if (size > (ssize_t)ff->size - ff->offset)
2008c2ecf20Sopenharmony_ci		return -1;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	memcpy(addr, ff->buf + ff->offset, size);
2038c2ecf20Sopenharmony_ci	ff->offset += size;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	return 0;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic int __do_read(struct feat_fd *ff, void *addr, ssize_t size)
2108c2ecf20Sopenharmony_ci{
2118c2ecf20Sopenharmony_ci	if (!ff->buf)
2128c2ecf20Sopenharmony_ci		return __do_read_fd(ff, addr, size);
2138c2ecf20Sopenharmony_ci	return __do_read_buf(ff, addr, size);
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int do_read_u32(struct feat_fd *ff, u32 *addr)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	int ret;
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ci	ret = __do_read(ff, addr, sizeof(*addr));
2218c2ecf20Sopenharmony_ci	if (ret)
2228c2ecf20Sopenharmony_ci		return ret;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if (ff->ph->needs_swap)
2258c2ecf20Sopenharmony_ci		*addr = bswap_32(*addr);
2268c2ecf20Sopenharmony_ci	return 0;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_cistatic int do_read_u64(struct feat_fd *ff, u64 *addr)
2308c2ecf20Sopenharmony_ci{
2318c2ecf20Sopenharmony_ci	int ret;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci	ret = __do_read(ff, addr, sizeof(*addr));
2348c2ecf20Sopenharmony_ci	if (ret)
2358c2ecf20Sopenharmony_ci		return ret;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (ff->ph->needs_swap)
2388c2ecf20Sopenharmony_ci		*addr = bswap_64(*addr);
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic char *do_read_string(struct feat_fd *ff)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	u32 len;
2458c2ecf20Sopenharmony_ci	char *buf;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &len))
2488c2ecf20Sopenharmony_ci		return NULL;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	buf = malloc(len);
2518c2ecf20Sopenharmony_ci	if (!buf)
2528c2ecf20Sopenharmony_ci		return NULL;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci	if (!__do_read(ff, buf, len)) {
2558c2ecf20Sopenharmony_ci		/*
2568c2ecf20Sopenharmony_ci		 * strings are padded by zeroes
2578c2ecf20Sopenharmony_ci		 * thus the actual strlen of buf
2588c2ecf20Sopenharmony_ci		 * may be less than len
2598c2ecf20Sopenharmony_ci		 */
2608c2ecf20Sopenharmony_ci		return buf;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	free(buf);
2648c2ecf20Sopenharmony_ci	return NULL;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */
2688c2ecf20Sopenharmony_cistatic int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	unsigned long *set;
2718c2ecf20Sopenharmony_ci	u64 size, *p;
2728c2ecf20Sopenharmony_ci	int i, ret;
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_ci	ret = do_read_u64(ff, &size);
2758c2ecf20Sopenharmony_ci	if (ret)
2768c2ecf20Sopenharmony_ci		return ret;
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_ci	set = bitmap_alloc(size);
2798c2ecf20Sopenharmony_ci	if (!set)
2808c2ecf20Sopenharmony_ci		return -ENOMEM;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	p = (u64 *) set;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
2858c2ecf20Sopenharmony_ci		ret = do_read_u64(ff, p + i);
2868c2ecf20Sopenharmony_ci		if (ret < 0) {
2878c2ecf20Sopenharmony_ci			free(set);
2888c2ecf20Sopenharmony_ci			return ret;
2898c2ecf20Sopenharmony_ci		}
2908c2ecf20Sopenharmony_ci	}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	*pset  = set;
2938c2ecf20Sopenharmony_ci	*psize = size;
2948c2ecf20Sopenharmony_ci	return 0;
2958c2ecf20Sopenharmony_ci}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_cistatic int write_tracing_data(struct feat_fd *ff,
2988c2ecf20Sopenharmony_ci			      struct evlist *evlist)
2998c2ecf20Sopenharmony_ci{
3008c2ecf20Sopenharmony_ci	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
3018c2ecf20Sopenharmony_ci		return -1;
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	return read_tracing_data(ff->fd, &evlist->core.entries);
3048c2ecf20Sopenharmony_ci}
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_cistatic int write_build_id(struct feat_fd *ff,
3078c2ecf20Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
3088c2ecf20Sopenharmony_ci{
3098c2ecf20Sopenharmony_ci	struct perf_session *session;
3108c2ecf20Sopenharmony_ci	int err;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	if (!perf_session__read_build_ids(session, true))
3158c2ecf20Sopenharmony_ci		return -1;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
3188c2ecf20Sopenharmony_ci		return -1;
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_ci	err = perf_session__write_buildid_table(session, ff);
3218c2ecf20Sopenharmony_ci	if (err < 0) {
3228c2ecf20Sopenharmony_ci		pr_debug("failed to write buildid table\n");
3238c2ecf20Sopenharmony_ci		return err;
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci	perf_session__cache_build_ids(session);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	return 0;
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int write_hostname(struct feat_fd *ff,
3318c2ecf20Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	struct utsname uts;
3348c2ecf20Sopenharmony_ci	int ret;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	ret = uname(&uts);
3378c2ecf20Sopenharmony_ci	if (ret < 0)
3388c2ecf20Sopenharmony_ci		return -1;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	return do_write_string(ff, uts.nodename);
3418c2ecf20Sopenharmony_ci}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_cistatic int write_osrelease(struct feat_fd *ff,
3448c2ecf20Sopenharmony_ci			   struct evlist *evlist __maybe_unused)
3458c2ecf20Sopenharmony_ci{
3468c2ecf20Sopenharmony_ci	struct utsname uts;
3478c2ecf20Sopenharmony_ci	int ret;
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_ci	ret = uname(&uts);
3508c2ecf20Sopenharmony_ci	if (ret < 0)
3518c2ecf20Sopenharmony_ci		return -1;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return do_write_string(ff, uts.release);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic int write_arch(struct feat_fd *ff,
3578c2ecf20Sopenharmony_ci		      struct evlist *evlist __maybe_unused)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct utsname uts;
3608c2ecf20Sopenharmony_ci	int ret;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	ret = uname(&uts);
3638c2ecf20Sopenharmony_ci	if (ret < 0)
3648c2ecf20Sopenharmony_ci		return -1;
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	return do_write_string(ff, uts.machine);
3678c2ecf20Sopenharmony_ci}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_cistatic int write_version(struct feat_fd *ff,
3708c2ecf20Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
3718c2ecf20Sopenharmony_ci{
3728c2ecf20Sopenharmony_ci	return do_write_string(ff, perf_version_string);
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cistatic int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	FILE *file;
3788c2ecf20Sopenharmony_ci	char *buf = NULL;
3798c2ecf20Sopenharmony_ci	char *s, *p;
3808c2ecf20Sopenharmony_ci	const char *search = cpuinfo_proc;
3818c2ecf20Sopenharmony_ci	size_t len = 0;
3828c2ecf20Sopenharmony_ci	int ret = -1;
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	if (!search)
3858c2ecf20Sopenharmony_ci		return -1;
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	file = fopen("/proc/cpuinfo", "r");
3888c2ecf20Sopenharmony_ci	if (!file)
3898c2ecf20Sopenharmony_ci		return -1;
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	while (getline(&buf, &len, file) > 0) {
3928c2ecf20Sopenharmony_ci		ret = strncmp(buf, search, strlen(search));
3938c2ecf20Sopenharmony_ci		if (!ret)
3948c2ecf20Sopenharmony_ci			break;
3958c2ecf20Sopenharmony_ci	}
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	if (ret) {
3988c2ecf20Sopenharmony_ci		ret = -1;
3998c2ecf20Sopenharmony_ci		goto done;
4008c2ecf20Sopenharmony_ci	}
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	s = buf;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	p = strchr(buf, ':');
4058c2ecf20Sopenharmony_ci	if (p && *(p+1) == ' ' && *(p+2))
4068c2ecf20Sopenharmony_ci		s = p + 2;
4078c2ecf20Sopenharmony_ci	p = strchr(s, '\n');
4088c2ecf20Sopenharmony_ci	if (p)
4098c2ecf20Sopenharmony_ci		*p = '\0';
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_ci	/* squash extra space characters (branding string) */
4128c2ecf20Sopenharmony_ci	p = s;
4138c2ecf20Sopenharmony_ci	while (*p) {
4148c2ecf20Sopenharmony_ci		if (isspace(*p)) {
4158c2ecf20Sopenharmony_ci			char *r = p + 1;
4168c2ecf20Sopenharmony_ci			char *q = skip_spaces(r);
4178c2ecf20Sopenharmony_ci			*p = ' ';
4188c2ecf20Sopenharmony_ci			if (q != (p+1))
4198c2ecf20Sopenharmony_ci				while ((*r++ = *q++));
4208c2ecf20Sopenharmony_ci		}
4218c2ecf20Sopenharmony_ci		p++;
4228c2ecf20Sopenharmony_ci	}
4238c2ecf20Sopenharmony_ci	ret = do_write_string(ff, s);
4248c2ecf20Sopenharmony_cidone:
4258c2ecf20Sopenharmony_ci	free(buf);
4268c2ecf20Sopenharmony_ci	fclose(file);
4278c2ecf20Sopenharmony_ci	return ret;
4288c2ecf20Sopenharmony_ci}
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_cistatic int write_cpudesc(struct feat_fd *ff,
4318c2ecf20Sopenharmony_ci		       struct evlist *evlist __maybe_unused)
4328c2ecf20Sopenharmony_ci{
4338c2ecf20Sopenharmony_ci#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__)
4348c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "cpu", }
4358c2ecf20Sopenharmony_ci#elif defined(__s390__)
4368c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "vendor_id", }
4378c2ecf20Sopenharmony_ci#elif defined(__sh__)
4388c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "cpu type", }
4398c2ecf20Sopenharmony_ci#elif defined(__alpha__) || defined(__mips__)
4408c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "cpu model", }
4418c2ecf20Sopenharmony_ci#elif defined(__arm__)
4428c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "model name", "Processor", }
4438c2ecf20Sopenharmony_ci#elif defined(__arc__)
4448c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "Processor", }
4458c2ecf20Sopenharmony_ci#elif defined(__xtensa__)
4468c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "core ID", }
4478c2ecf20Sopenharmony_ci#else
4488c2ecf20Sopenharmony_ci#define CPUINFO_PROC	{ "model name", }
4498c2ecf20Sopenharmony_ci#endif
4508c2ecf20Sopenharmony_ci	const char *cpuinfo_procs[] = CPUINFO_PROC;
4518c2ecf20Sopenharmony_ci#undef CPUINFO_PROC
4528c2ecf20Sopenharmony_ci	unsigned int i;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) {
4558c2ecf20Sopenharmony_ci		int ret;
4568c2ecf20Sopenharmony_ci		ret = __write_cpudesc(ff, cpuinfo_procs[i]);
4578c2ecf20Sopenharmony_ci		if (ret >= 0)
4588c2ecf20Sopenharmony_ci			return ret;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci	return -1;
4618c2ecf20Sopenharmony_ci}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci
4648c2ecf20Sopenharmony_cistatic int write_nrcpus(struct feat_fd *ff,
4658c2ecf20Sopenharmony_ci			struct evlist *evlist __maybe_unused)
4668c2ecf20Sopenharmony_ci{
4678c2ecf20Sopenharmony_ci	long nr;
4688c2ecf20Sopenharmony_ci	u32 nrc, nra;
4698c2ecf20Sopenharmony_ci	int ret;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	nrc = cpu__max_present_cpu();
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	nr = sysconf(_SC_NPROCESSORS_ONLN);
4748c2ecf20Sopenharmony_ci	if (nr < 0)
4758c2ecf20Sopenharmony_ci		return -1;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	nra = (u32)(nr & UINT_MAX);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	ret = do_write(ff, &nrc, sizeof(nrc));
4808c2ecf20Sopenharmony_ci	if (ret < 0)
4818c2ecf20Sopenharmony_ci		return ret;
4828c2ecf20Sopenharmony_ci
4838c2ecf20Sopenharmony_ci	return do_write(ff, &nra, sizeof(nra));
4848c2ecf20Sopenharmony_ci}
4858c2ecf20Sopenharmony_ci
4868c2ecf20Sopenharmony_cistatic int write_event_desc(struct feat_fd *ff,
4878c2ecf20Sopenharmony_ci			    struct evlist *evlist)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct evsel *evsel;
4908c2ecf20Sopenharmony_ci	u32 nre, nri, sz;
4918c2ecf20Sopenharmony_ci	int ret;
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci	nre = evlist->core.nr_entries;
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_ci	/*
4968c2ecf20Sopenharmony_ci	 * write number of events
4978c2ecf20Sopenharmony_ci	 */
4988c2ecf20Sopenharmony_ci	ret = do_write(ff, &nre, sizeof(nre));
4998c2ecf20Sopenharmony_ci	if (ret < 0)
5008c2ecf20Sopenharmony_ci		return ret;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	/*
5038c2ecf20Sopenharmony_ci	 * size of perf_event_attr struct
5048c2ecf20Sopenharmony_ci	 */
5058c2ecf20Sopenharmony_ci	sz = (u32)sizeof(evsel->core.attr);
5068c2ecf20Sopenharmony_ci	ret = do_write(ff, &sz, sizeof(sz));
5078c2ecf20Sopenharmony_ci	if (ret < 0)
5088c2ecf20Sopenharmony_ci		return ret;
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
5118c2ecf20Sopenharmony_ci		ret = do_write(ff, &evsel->core.attr, sz);
5128c2ecf20Sopenharmony_ci		if (ret < 0)
5138c2ecf20Sopenharmony_ci			return ret;
5148c2ecf20Sopenharmony_ci		/*
5158c2ecf20Sopenharmony_ci		 * write number of unique id per event
5168c2ecf20Sopenharmony_ci		 * there is one id per instance of an event
5178c2ecf20Sopenharmony_ci		 *
5188c2ecf20Sopenharmony_ci		 * copy into an nri to be independent of the
5198c2ecf20Sopenharmony_ci		 * type of ids,
5208c2ecf20Sopenharmony_ci		 */
5218c2ecf20Sopenharmony_ci		nri = evsel->core.ids;
5228c2ecf20Sopenharmony_ci		ret = do_write(ff, &nri, sizeof(nri));
5238c2ecf20Sopenharmony_ci		if (ret < 0)
5248c2ecf20Sopenharmony_ci			return ret;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci		/*
5278c2ecf20Sopenharmony_ci		 * write event string as passed on cmdline
5288c2ecf20Sopenharmony_ci		 */
5298c2ecf20Sopenharmony_ci		ret = do_write_string(ff, evsel__name(evsel));
5308c2ecf20Sopenharmony_ci		if (ret < 0)
5318c2ecf20Sopenharmony_ci			return ret;
5328c2ecf20Sopenharmony_ci		/*
5338c2ecf20Sopenharmony_ci		 * write unique ids for this event
5348c2ecf20Sopenharmony_ci		 */
5358c2ecf20Sopenharmony_ci		ret = do_write(ff, evsel->core.id, evsel->core.ids * sizeof(u64));
5368c2ecf20Sopenharmony_ci		if (ret < 0)
5378c2ecf20Sopenharmony_ci			return ret;
5388c2ecf20Sopenharmony_ci	}
5398c2ecf20Sopenharmony_ci	return 0;
5408c2ecf20Sopenharmony_ci}
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_cistatic int write_cmdline(struct feat_fd *ff,
5438c2ecf20Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	char pbuf[MAXPATHLEN], *buf;
5468c2ecf20Sopenharmony_ci	int i, ret, n;
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/* actual path to perf binary */
5498c2ecf20Sopenharmony_ci	buf = perf_exe(pbuf, MAXPATHLEN);
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci	/* account for binary path */
5528c2ecf20Sopenharmony_ci	n = perf_env.nr_cmdline + 1;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	ret = do_write(ff, &n, sizeof(n));
5558c2ecf20Sopenharmony_ci	if (ret < 0)
5568c2ecf20Sopenharmony_ci		return ret;
5578c2ecf20Sopenharmony_ci
5588c2ecf20Sopenharmony_ci	ret = do_write_string(ff, buf);
5598c2ecf20Sopenharmony_ci	if (ret < 0)
5608c2ecf20Sopenharmony_ci		return ret;
5618c2ecf20Sopenharmony_ci
5628c2ecf20Sopenharmony_ci	for (i = 0 ; i < perf_env.nr_cmdline; i++) {
5638c2ecf20Sopenharmony_ci		ret = do_write_string(ff, perf_env.cmdline_argv[i]);
5648c2ecf20Sopenharmony_ci		if (ret < 0)
5658c2ecf20Sopenharmony_ci			return ret;
5668c2ecf20Sopenharmony_ci	}
5678c2ecf20Sopenharmony_ci	return 0;
5688c2ecf20Sopenharmony_ci}
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cistatic int write_cpu_topology(struct feat_fd *ff,
5728c2ecf20Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	struct cpu_topology *tp;
5758c2ecf20Sopenharmony_ci	u32 i;
5768c2ecf20Sopenharmony_ci	int ret, j;
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	tp = cpu_topology__new();
5798c2ecf20Sopenharmony_ci	if (!tp)
5808c2ecf20Sopenharmony_ci		return -1;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	ret = do_write(ff, &tp->core_sib, sizeof(tp->core_sib));
5838c2ecf20Sopenharmony_ci	if (ret < 0)
5848c2ecf20Sopenharmony_ci		goto done;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	for (i = 0; i < tp->core_sib; i++) {
5878c2ecf20Sopenharmony_ci		ret = do_write_string(ff, tp->core_siblings[i]);
5888c2ecf20Sopenharmony_ci		if (ret < 0)
5898c2ecf20Sopenharmony_ci			goto done;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci	ret = do_write(ff, &tp->thread_sib, sizeof(tp->thread_sib));
5928c2ecf20Sopenharmony_ci	if (ret < 0)
5938c2ecf20Sopenharmony_ci		goto done;
5948c2ecf20Sopenharmony_ci
5958c2ecf20Sopenharmony_ci	for (i = 0; i < tp->thread_sib; i++) {
5968c2ecf20Sopenharmony_ci		ret = do_write_string(ff, tp->thread_siblings[i]);
5978c2ecf20Sopenharmony_ci		if (ret < 0)
5988c2ecf20Sopenharmony_ci			break;
5998c2ecf20Sopenharmony_ci	}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci	ret = perf_env__read_cpu_topology_map(&perf_env);
6028c2ecf20Sopenharmony_ci	if (ret < 0)
6038c2ecf20Sopenharmony_ci		goto done;
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ci	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
6068c2ecf20Sopenharmony_ci		ret = do_write(ff, &perf_env.cpu[j].core_id,
6078c2ecf20Sopenharmony_ci			       sizeof(perf_env.cpu[j].core_id));
6088c2ecf20Sopenharmony_ci		if (ret < 0)
6098c2ecf20Sopenharmony_ci			return ret;
6108c2ecf20Sopenharmony_ci		ret = do_write(ff, &perf_env.cpu[j].socket_id,
6118c2ecf20Sopenharmony_ci			       sizeof(perf_env.cpu[j].socket_id));
6128c2ecf20Sopenharmony_ci		if (ret < 0)
6138c2ecf20Sopenharmony_ci			return ret;
6148c2ecf20Sopenharmony_ci	}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (!tp->die_sib)
6178c2ecf20Sopenharmony_ci		goto done;
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	ret = do_write(ff, &tp->die_sib, sizeof(tp->die_sib));
6208c2ecf20Sopenharmony_ci	if (ret < 0)
6218c2ecf20Sopenharmony_ci		goto done;
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ci	for (i = 0; i < tp->die_sib; i++) {
6248c2ecf20Sopenharmony_ci		ret = do_write_string(ff, tp->die_siblings[i]);
6258c2ecf20Sopenharmony_ci		if (ret < 0)
6268c2ecf20Sopenharmony_ci			goto done;
6278c2ecf20Sopenharmony_ci	}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
6308c2ecf20Sopenharmony_ci		ret = do_write(ff, &perf_env.cpu[j].die_id,
6318c2ecf20Sopenharmony_ci			       sizeof(perf_env.cpu[j].die_id));
6328c2ecf20Sopenharmony_ci		if (ret < 0)
6338c2ecf20Sopenharmony_ci			return ret;
6348c2ecf20Sopenharmony_ci	}
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_cidone:
6378c2ecf20Sopenharmony_ci	cpu_topology__delete(tp);
6388c2ecf20Sopenharmony_ci	return ret;
6398c2ecf20Sopenharmony_ci}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_cistatic int write_total_mem(struct feat_fd *ff,
6448c2ecf20Sopenharmony_ci			   struct evlist *evlist __maybe_unused)
6458c2ecf20Sopenharmony_ci{
6468c2ecf20Sopenharmony_ci	char *buf = NULL;
6478c2ecf20Sopenharmony_ci	FILE *fp;
6488c2ecf20Sopenharmony_ci	size_t len = 0;
6498c2ecf20Sopenharmony_ci	int ret = -1, n;
6508c2ecf20Sopenharmony_ci	uint64_t mem;
6518c2ecf20Sopenharmony_ci
6528c2ecf20Sopenharmony_ci	fp = fopen("/proc/meminfo", "r");
6538c2ecf20Sopenharmony_ci	if (!fp)
6548c2ecf20Sopenharmony_ci		return -1;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	while (getline(&buf, &len, fp) > 0) {
6578c2ecf20Sopenharmony_ci		ret = strncmp(buf, "MemTotal:", 9);
6588c2ecf20Sopenharmony_ci		if (!ret)
6598c2ecf20Sopenharmony_ci			break;
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci	if (!ret) {
6628c2ecf20Sopenharmony_ci		n = sscanf(buf, "%*s %"PRIu64, &mem);
6638c2ecf20Sopenharmony_ci		if (n == 1)
6648c2ecf20Sopenharmony_ci			ret = do_write(ff, &mem, sizeof(mem));
6658c2ecf20Sopenharmony_ci	} else
6668c2ecf20Sopenharmony_ci		ret = -1;
6678c2ecf20Sopenharmony_ci	free(buf);
6688c2ecf20Sopenharmony_ci	fclose(fp);
6698c2ecf20Sopenharmony_ci	return ret;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int write_numa_topology(struct feat_fd *ff,
6738c2ecf20Sopenharmony_ci			       struct evlist *evlist __maybe_unused)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct numa_topology *tp;
6768c2ecf20Sopenharmony_ci	int ret = -1;
6778c2ecf20Sopenharmony_ci	u32 i;
6788c2ecf20Sopenharmony_ci
6798c2ecf20Sopenharmony_ci	tp = numa_topology__new();
6808c2ecf20Sopenharmony_ci	if (!tp)
6818c2ecf20Sopenharmony_ci		return -ENOMEM;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	ret = do_write(ff, &tp->nr, sizeof(u32));
6848c2ecf20Sopenharmony_ci	if (ret < 0)
6858c2ecf20Sopenharmony_ci		goto err;
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_ci	for (i = 0; i < tp->nr; i++) {
6888c2ecf20Sopenharmony_ci		struct numa_topology_node *n = &tp->nodes[i];
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci		ret = do_write(ff, &n->node, sizeof(u32));
6918c2ecf20Sopenharmony_ci		if (ret < 0)
6928c2ecf20Sopenharmony_ci			goto err;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci		ret = do_write(ff, &n->mem_total, sizeof(u64));
6958c2ecf20Sopenharmony_ci		if (ret)
6968c2ecf20Sopenharmony_ci			goto err;
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci		ret = do_write(ff, &n->mem_free, sizeof(u64));
6998c2ecf20Sopenharmony_ci		if (ret)
7008c2ecf20Sopenharmony_ci			goto err;
7018c2ecf20Sopenharmony_ci
7028c2ecf20Sopenharmony_ci		ret = do_write_string(ff, n->cpus);
7038c2ecf20Sopenharmony_ci		if (ret < 0)
7048c2ecf20Sopenharmony_ci			goto err;
7058c2ecf20Sopenharmony_ci	}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	ret = 0;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_cierr:
7108c2ecf20Sopenharmony_ci	numa_topology__delete(tp);
7118c2ecf20Sopenharmony_ci	return ret;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_ci/*
7158c2ecf20Sopenharmony_ci * File format:
7168c2ecf20Sopenharmony_ci *
7178c2ecf20Sopenharmony_ci * struct pmu_mappings {
7188c2ecf20Sopenharmony_ci *	u32	pmu_num;
7198c2ecf20Sopenharmony_ci *	struct pmu_map {
7208c2ecf20Sopenharmony_ci *		u32	type;
7218c2ecf20Sopenharmony_ci *		char	name[];
7228c2ecf20Sopenharmony_ci *	}[pmu_num];
7238c2ecf20Sopenharmony_ci * };
7248c2ecf20Sopenharmony_ci */
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_cistatic int write_pmu_mappings(struct feat_fd *ff,
7278c2ecf20Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
7288c2ecf20Sopenharmony_ci{
7298c2ecf20Sopenharmony_ci	struct perf_pmu *pmu = NULL;
7308c2ecf20Sopenharmony_ci	u32 pmu_num = 0;
7318c2ecf20Sopenharmony_ci	int ret;
7328c2ecf20Sopenharmony_ci
7338c2ecf20Sopenharmony_ci	/*
7348c2ecf20Sopenharmony_ci	 * Do a first pass to count number of pmu to avoid lseek so this
7358c2ecf20Sopenharmony_ci	 * works in pipe mode as well.
7368c2ecf20Sopenharmony_ci	 */
7378c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu))) {
7388c2ecf20Sopenharmony_ci		if (!pmu->name)
7398c2ecf20Sopenharmony_ci			continue;
7408c2ecf20Sopenharmony_ci		pmu_num++;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	ret = do_write(ff, &pmu_num, sizeof(pmu_num));
7448c2ecf20Sopenharmony_ci	if (ret < 0)
7458c2ecf20Sopenharmony_ci		return ret;
7468c2ecf20Sopenharmony_ci
7478c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu))) {
7488c2ecf20Sopenharmony_ci		if (!pmu->name)
7498c2ecf20Sopenharmony_ci			continue;
7508c2ecf20Sopenharmony_ci
7518c2ecf20Sopenharmony_ci		ret = do_write(ff, &pmu->type, sizeof(pmu->type));
7528c2ecf20Sopenharmony_ci		if (ret < 0)
7538c2ecf20Sopenharmony_ci			return ret;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci		ret = do_write_string(ff, pmu->name);
7568c2ecf20Sopenharmony_ci		if (ret < 0)
7578c2ecf20Sopenharmony_ci			return ret;
7588c2ecf20Sopenharmony_ci	}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	return 0;
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_ci/*
7648c2ecf20Sopenharmony_ci * File format:
7658c2ecf20Sopenharmony_ci *
7668c2ecf20Sopenharmony_ci * struct group_descs {
7678c2ecf20Sopenharmony_ci *	u32	nr_groups;
7688c2ecf20Sopenharmony_ci *	struct group_desc {
7698c2ecf20Sopenharmony_ci *		char	name[];
7708c2ecf20Sopenharmony_ci *		u32	leader_idx;
7718c2ecf20Sopenharmony_ci *		u32	nr_members;
7728c2ecf20Sopenharmony_ci *	}[nr_groups];
7738c2ecf20Sopenharmony_ci * };
7748c2ecf20Sopenharmony_ci */
7758c2ecf20Sopenharmony_cistatic int write_group_desc(struct feat_fd *ff,
7768c2ecf20Sopenharmony_ci			    struct evlist *evlist)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	u32 nr_groups = evlist->nr_groups;
7798c2ecf20Sopenharmony_ci	struct evsel *evsel;
7808c2ecf20Sopenharmony_ci	int ret;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	ret = do_write(ff, &nr_groups, sizeof(nr_groups));
7838c2ecf20Sopenharmony_ci	if (ret < 0)
7848c2ecf20Sopenharmony_ci		return ret;
7858c2ecf20Sopenharmony_ci
7868c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
7878c2ecf20Sopenharmony_ci		if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) {
7888c2ecf20Sopenharmony_ci			const char *name = evsel->group_name ?: "{anon_group}";
7898c2ecf20Sopenharmony_ci			u32 leader_idx = evsel->idx;
7908c2ecf20Sopenharmony_ci			u32 nr_members = evsel->core.nr_members;
7918c2ecf20Sopenharmony_ci
7928c2ecf20Sopenharmony_ci			ret = do_write_string(ff, name);
7938c2ecf20Sopenharmony_ci			if (ret < 0)
7948c2ecf20Sopenharmony_ci				return ret;
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_ci			ret = do_write(ff, &leader_idx, sizeof(leader_idx));
7978c2ecf20Sopenharmony_ci			if (ret < 0)
7988c2ecf20Sopenharmony_ci				return ret;
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_ci			ret = do_write(ff, &nr_members, sizeof(nr_members));
8018c2ecf20Sopenharmony_ci			if (ret < 0)
8028c2ecf20Sopenharmony_ci				return ret;
8038c2ecf20Sopenharmony_ci		}
8048c2ecf20Sopenharmony_ci	}
8058c2ecf20Sopenharmony_ci	return 0;
8068c2ecf20Sopenharmony_ci}
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci/*
8098c2ecf20Sopenharmony_ci * Return the CPU id as a raw string.
8108c2ecf20Sopenharmony_ci *
8118c2ecf20Sopenharmony_ci * Each architecture should provide a more precise id string that
8128c2ecf20Sopenharmony_ci * can be use to match the architecture's "mapfile".
8138c2ecf20Sopenharmony_ci */
8148c2ecf20Sopenharmony_cichar * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
8158c2ecf20Sopenharmony_ci{
8168c2ecf20Sopenharmony_ci	return NULL;
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci
8198c2ecf20Sopenharmony_ci/* Return zero when the cpuid from the mapfile.csv matches the
8208c2ecf20Sopenharmony_ci * cpuid string generated on this platform.
8218c2ecf20Sopenharmony_ci * Otherwise return non-zero.
8228c2ecf20Sopenharmony_ci */
8238c2ecf20Sopenharmony_ciint __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	regex_t re;
8268c2ecf20Sopenharmony_ci	regmatch_t pmatch[1];
8278c2ecf20Sopenharmony_ci	int match;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) {
8308c2ecf20Sopenharmony_ci		/* Warn unable to generate match particular string. */
8318c2ecf20Sopenharmony_ci		pr_info("Invalid regular expression %s\n", mapcpuid);
8328c2ecf20Sopenharmony_ci		return 1;
8338c2ecf20Sopenharmony_ci	}
8348c2ecf20Sopenharmony_ci
8358c2ecf20Sopenharmony_ci	match = !regexec(&re, cpuid, 1, pmatch, 0);
8368c2ecf20Sopenharmony_ci	regfree(&re);
8378c2ecf20Sopenharmony_ci	if (match) {
8388c2ecf20Sopenharmony_ci		size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci		/* Verify the entire string matched. */
8418c2ecf20Sopenharmony_ci		if (match_len == strlen(cpuid))
8428c2ecf20Sopenharmony_ci			return 0;
8438c2ecf20Sopenharmony_ci	}
8448c2ecf20Sopenharmony_ci	return 1;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci/*
8488c2ecf20Sopenharmony_ci * default get_cpuid(): nothing gets recorded
8498c2ecf20Sopenharmony_ci * actual implementation must be in arch/$(SRCARCH)/util/header.c
8508c2ecf20Sopenharmony_ci */
8518c2ecf20Sopenharmony_ciint __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused)
8528c2ecf20Sopenharmony_ci{
8538c2ecf20Sopenharmony_ci	return ENOSYS; /* Not implemented */
8548c2ecf20Sopenharmony_ci}
8558c2ecf20Sopenharmony_ci
8568c2ecf20Sopenharmony_cistatic int write_cpuid(struct feat_fd *ff,
8578c2ecf20Sopenharmony_ci		       struct evlist *evlist __maybe_unused)
8588c2ecf20Sopenharmony_ci{
8598c2ecf20Sopenharmony_ci	char buffer[64];
8608c2ecf20Sopenharmony_ci	int ret;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	ret = get_cpuid(buffer, sizeof(buffer));
8638c2ecf20Sopenharmony_ci	if (ret)
8648c2ecf20Sopenharmony_ci		return -1;
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_ci	return do_write_string(ff, buffer);
8678c2ecf20Sopenharmony_ci}
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic int write_branch_stack(struct feat_fd *ff __maybe_unused,
8708c2ecf20Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
8718c2ecf20Sopenharmony_ci{
8728c2ecf20Sopenharmony_ci	return 0;
8738c2ecf20Sopenharmony_ci}
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_cistatic int write_auxtrace(struct feat_fd *ff,
8768c2ecf20Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
8778c2ecf20Sopenharmony_ci{
8788c2ecf20Sopenharmony_ci	struct perf_session *session;
8798c2ecf20Sopenharmony_ci	int err;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
8828c2ecf20Sopenharmony_ci		return -1;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	err = auxtrace_index__write(ff->fd, &session->auxtrace_index);
8878c2ecf20Sopenharmony_ci	if (err < 0)
8888c2ecf20Sopenharmony_ci		pr_err("Failed to write auxtrace index\n");
8898c2ecf20Sopenharmony_ci	return err;
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic int write_clockid(struct feat_fd *ff,
8938c2ecf20Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
8948c2ecf20Sopenharmony_ci{
8958c2ecf20Sopenharmony_ci	return do_write(ff, &ff->ph->env.clock.clockid_res_ns,
8968c2ecf20Sopenharmony_ci			sizeof(ff->ph->env.clock.clockid_res_ns));
8978c2ecf20Sopenharmony_ci}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_cistatic int write_clock_data(struct feat_fd *ff,
9008c2ecf20Sopenharmony_ci			    struct evlist *evlist __maybe_unused)
9018c2ecf20Sopenharmony_ci{
9028c2ecf20Sopenharmony_ci	u64 *data64;
9038c2ecf20Sopenharmony_ci	u32 data32;
9048c2ecf20Sopenharmony_ci	int ret;
9058c2ecf20Sopenharmony_ci
9068c2ecf20Sopenharmony_ci	/* version */
9078c2ecf20Sopenharmony_ci	data32 = 1;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	ret = do_write(ff, &data32, sizeof(data32));
9108c2ecf20Sopenharmony_ci	if (ret < 0)
9118c2ecf20Sopenharmony_ci		return ret;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	/* clockid */
9148c2ecf20Sopenharmony_ci	data32 = ff->ph->env.clock.clockid;
9158c2ecf20Sopenharmony_ci
9168c2ecf20Sopenharmony_ci	ret = do_write(ff, &data32, sizeof(data32));
9178c2ecf20Sopenharmony_ci	if (ret < 0)
9188c2ecf20Sopenharmony_ci		return ret;
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	/* TOD ref time */
9218c2ecf20Sopenharmony_ci	data64 = &ff->ph->env.clock.tod_ns;
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	ret = do_write(ff, data64, sizeof(*data64));
9248c2ecf20Sopenharmony_ci	if (ret < 0)
9258c2ecf20Sopenharmony_ci		return ret;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	/* clockid ref time */
9288c2ecf20Sopenharmony_ci	data64 = &ff->ph->env.clock.clockid_ns;
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ci	return do_write(ff, data64, sizeof(*data64));
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_cistatic int write_dir_format(struct feat_fd *ff,
9348c2ecf20Sopenharmony_ci			    struct evlist *evlist __maybe_unused)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	struct perf_session *session;
9378c2ecf20Sopenharmony_ci	struct perf_data *data;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
9408c2ecf20Sopenharmony_ci	data = session->data;
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (WARN_ON(!perf_data__is_dir(data)))
9438c2ecf20Sopenharmony_ci		return -1;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	return do_write(ff, &data->dir.version, sizeof(data->dir.version));
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
9498c2ecf20Sopenharmony_cistatic int write_bpf_prog_info(struct feat_fd *ff,
9508c2ecf20Sopenharmony_ci			       struct evlist *evlist __maybe_unused)
9518c2ecf20Sopenharmony_ci{
9528c2ecf20Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
9538c2ecf20Sopenharmony_ci	struct rb_root *root;
9548c2ecf20Sopenharmony_ci	struct rb_node *next;
9558c2ecf20Sopenharmony_ci	int ret;
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_ci	down_read(&env->bpf_progs.lock);
9588c2ecf20Sopenharmony_ci
9598c2ecf20Sopenharmony_ci	ret = do_write(ff, &env->bpf_progs.infos_cnt,
9608c2ecf20Sopenharmony_ci		       sizeof(env->bpf_progs.infos_cnt));
9618c2ecf20Sopenharmony_ci	if (ret < 0)
9628c2ecf20Sopenharmony_ci		goto out;
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ci	root = &env->bpf_progs.infos;
9658c2ecf20Sopenharmony_ci	next = rb_first(root);
9668c2ecf20Sopenharmony_ci	while (next) {
9678c2ecf20Sopenharmony_ci		struct bpf_prog_info_node *node;
9688c2ecf20Sopenharmony_ci		size_t len;
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
9718c2ecf20Sopenharmony_ci		next = rb_next(&node->rb_node);
9728c2ecf20Sopenharmony_ci		len = sizeof(struct bpf_prog_info_linear) +
9738c2ecf20Sopenharmony_ci			node->info_linear->data_len;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci		/* before writing to file, translate address to offset */
9768c2ecf20Sopenharmony_ci		bpf_program__bpil_addr_to_offs(node->info_linear);
9778c2ecf20Sopenharmony_ci		ret = do_write(ff, node->info_linear, len);
9788c2ecf20Sopenharmony_ci		/*
9798c2ecf20Sopenharmony_ci		 * translate back to address even when do_write() fails,
9808c2ecf20Sopenharmony_ci		 * so that this function never changes the data.
9818c2ecf20Sopenharmony_ci		 */
9828c2ecf20Sopenharmony_ci		bpf_program__bpil_offs_to_addr(node->info_linear);
9838c2ecf20Sopenharmony_ci		if (ret < 0)
9848c2ecf20Sopenharmony_ci			goto out;
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ciout:
9878c2ecf20Sopenharmony_ci	up_read(&env->bpf_progs.lock);
9888c2ecf20Sopenharmony_ci	return ret;
9898c2ecf20Sopenharmony_ci}
9908c2ecf20Sopenharmony_ci#else // HAVE_LIBBPF_SUPPORT
9918c2ecf20Sopenharmony_cistatic int write_bpf_prog_info(struct feat_fd *ff __maybe_unused,
9928c2ecf20Sopenharmony_ci			       struct evlist *evlist __maybe_unused)
9938c2ecf20Sopenharmony_ci{
9948c2ecf20Sopenharmony_ci	return 0;
9958c2ecf20Sopenharmony_ci}
9968c2ecf20Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT
9978c2ecf20Sopenharmony_ci
9988c2ecf20Sopenharmony_cistatic int write_bpf_btf(struct feat_fd *ff,
9998c2ecf20Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
10008c2ecf20Sopenharmony_ci{
10018c2ecf20Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
10028c2ecf20Sopenharmony_ci	struct rb_root *root;
10038c2ecf20Sopenharmony_ci	struct rb_node *next;
10048c2ecf20Sopenharmony_ci	int ret;
10058c2ecf20Sopenharmony_ci
10068c2ecf20Sopenharmony_ci	down_read(&env->bpf_progs.lock);
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	ret = do_write(ff, &env->bpf_progs.btfs_cnt,
10098c2ecf20Sopenharmony_ci		       sizeof(env->bpf_progs.btfs_cnt));
10108c2ecf20Sopenharmony_ci
10118c2ecf20Sopenharmony_ci	if (ret < 0)
10128c2ecf20Sopenharmony_ci		goto out;
10138c2ecf20Sopenharmony_ci
10148c2ecf20Sopenharmony_ci	root = &env->bpf_progs.btfs;
10158c2ecf20Sopenharmony_ci	next = rb_first(root);
10168c2ecf20Sopenharmony_ci	while (next) {
10178c2ecf20Sopenharmony_ci		struct btf_node *node;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		node = rb_entry(next, struct btf_node, rb_node);
10208c2ecf20Sopenharmony_ci		next = rb_next(&node->rb_node);
10218c2ecf20Sopenharmony_ci		ret = do_write(ff, &node->id,
10228c2ecf20Sopenharmony_ci			       sizeof(u32) * 2 + node->data_size);
10238c2ecf20Sopenharmony_ci		if (ret < 0)
10248c2ecf20Sopenharmony_ci			goto out;
10258c2ecf20Sopenharmony_ci	}
10268c2ecf20Sopenharmony_ciout:
10278c2ecf20Sopenharmony_ci	up_read(&env->bpf_progs.lock);
10288c2ecf20Sopenharmony_ci	return ret;
10298c2ecf20Sopenharmony_ci}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_cistatic int cpu_cache_level__sort(const void *a, const void *b)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
10348c2ecf20Sopenharmony_ci	struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b;
10358c2ecf20Sopenharmony_ci
10368c2ecf20Sopenharmony_ci	return cache_a->level - cache_b->level;
10378c2ecf20Sopenharmony_ci}
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_cistatic bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b)
10408c2ecf20Sopenharmony_ci{
10418c2ecf20Sopenharmony_ci	if (a->level != b->level)
10428c2ecf20Sopenharmony_ci		return false;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci	if (a->line_size != b->line_size)
10458c2ecf20Sopenharmony_ci		return false;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci	if (a->sets != b->sets)
10488c2ecf20Sopenharmony_ci		return false;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	if (a->ways != b->ways)
10518c2ecf20Sopenharmony_ci		return false;
10528c2ecf20Sopenharmony_ci
10538c2ecf20Sopenharmony_ci	if (strcmp(a->type, b->type))
10548c2ecf20Sopenharmony_ci		return false;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	if (strcmp(a->size, b->size))
10578c2ecf20Sopenharmony_ci		return false;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	if (strcmp(a->map, b->map))
10608c2ecf20Sopenharmony_ci		return false;
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	return true;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	char path[PATH_MAX], file[PATH_MAX];
10688c2ecf20Sopenharmony_ci	struct stat st;
10698c2ecf20Sopenharmony_ci	size_t len;
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
10728c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	if (stat(file, &st))
10758c2ecf20Sopenharmony_ci		return 1;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/level", path);
10788c2ecf20Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->level))
10798c2ecf20Sopenharmony_ci		return -1;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
10828c2ecf20Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->line_size))
10838c2ecf20Sopenharmony_ci		return -1;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
10868c2ecf20Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->sets))
10878c2ecf20Sopenharmony_ci		return -1;
10888c2ecf20Sopenharmony_ci
10898c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
10908c2ecf20Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->ways))
10918c2ecf20Sopenharmony_ci		return -1;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/type", path);
10948c2ecf20Sopenharmony_ci	if (sysfs__read_str(file, &cache->type, &len))
10958c2ecf20Sopenharmony_ci		return -1;
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_ci	cache->type[len] = 0;
10988c2ecf20Sopenharmony_ci	cache->type = strim(cache->type);
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/size", path);
11018c2ecf20Sopenharmony_ci	if (sysfs__read_str(file, &cache->size, &len)) {
11028c2ecf20Sopenharmony_ci		zfree(&cache->type);
11038c2ecf20Sopenharmony_ci		return -1;
11048c2ecf20Sopenharmony_ci	}
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	cache->size[len] = 0;
11078c2ecf20Sopenharmony_ci	cache->size = strim(cache->size);
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
11108c2ecf20Sopenharmony_ci	if (sysfs__read_str(file, &cache->map, &len)) {
11118c2ecf20Sopenharmony_ci		zfree(&cache->size);
11128c2ecf20Sopenharmony_ci		zfree(&cache->type);
11138c2ecf20Sopenharmony_ci		return -1;
11148c2ecf20Sopenharmony_ci	}
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	cache->map[len] = 0;
11178c2ecf20Sopenharmony_ci	cache->map = strim(cache->map);
11188c2ecf20Sopenharmony_ci	return 0;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_cistatic void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c)
11228c2ecf20Sopenharmony_ci{
11238c2ecf20Sopenharmony_ci	fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
11248c2ecf20Sopenharmony_ci}
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci#define MAX_CACHE_LVL 4
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_cistatic int build_caches(struct cpu_cache_level caches[], u32 *cntp)
11298c2ecf20Sopenharmony_ci{
11308c2ecf20Sopenharmony_ci	u32 i, cnt = 0;
11318c2ecf20Sopenharmony_ci	u32 nr, cpu;
11328c2ecf20Sopenharmony_ci	u16 level;
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_ci	nr = cpu__max_cpu();
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_ci	for (cpu = 0; cpu < nr; cpu++) {
11378c2ecf20Sopenharmony_ci		for (level = 0; level < MAX_CACHE_LVL; level++) {
11388c2ecf20Sopenharmony_ci			struct cpu_cache_level c;
11398c2ecf20Sopenharmony_ci			int err;
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci			err = cpu_cache_level__read(&c, cpu, level);
11428c2ecf20Sopenharmony_ci			if (err < 0)
11438c2ecf20Sopenharmony_ci				return err;
11448c2ecf20Sopenharmony_ci
11458c2ecf20Sopenharmony_ci			if (err == 1)
11468c2ecf20Sopenharmony_ci				break;
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci			for (i = 0; i < cnt; i++) {
11498c2ecf20Sopenharmony_ci				if (cpu_cache_level__cmp(&c, &caches[i]))
11508c2ecf20Sopenharmony_ci					break;
11518c2ecf20Sopenharmony_ci			}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci			if (i == cnt)
11548c2ecf20Sopenharmony_ci				caches[cnt++] = c;
11558c2ecf20Sopenharmony_ci			else
11568c2ecf20Sopenharmony_ci				cpu_cache_level__free(&c);
11578c2ecf20Sopenharmony_ci		}
11588c2ecf20Sopenharmony_ci	}
11598c2ecf20Sopenharmony_ci	*cntp = cnt;
11608c2ecf20Sopenharmony_ci	return 0;
11618c2ecf20Sopenharmony_ci}
11628c2ecf20Sopenharmony_ci
11638c2ecf20Sopenharmony_cistatic int write_cache(struct feat_fd *ff,
11648c2ecf20Sopenharmony_ci		       struct evlist *evlist __maybe_unused)
11658c2ecf20Sopenharmony_ci{
11668c2ecf20Sopenharmony_ci	u32 max_caches = cpu__max_cpu() * MAX_CACHE_LVL;
11678c2ecf20Sopenharmony_ci	struct cpu_cache_level caches[max_caches];
11688c2ecf20Sopenharmony_ci	u32 cnt = 0, i, version = 1;
11698c2ecf20Sopenharmony_ci	int ret;
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	ret = build_caches(caches, &cnt);
11728c2ecf20Sopenharmony_ci	if (ret)
11738c2ecf20Sopenharmony_ci		goto out;
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci	qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort);
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	ret = do_write(ff, &version, sizeof(u32));
11788c2ecf20Sopenharmony_ci	if (ret < 0)
11798c2ecf20Sopenharmony_ci		goto out;
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_ci	ret = do_write(ff, &cnt, sizeof(u32));
11828c2ecf20Sopenharmony_ci	if (ret < 0)
11838c2ecf20Sopenharmony_ci		goto out;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	for (i = 0; i < cnt; i++) {
11868c2ecf20Sopenharmony_ci		struct cpu_cache_level *c = &caches[i];
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci		#define _W(v)					\
11898c2ecf20Sopenharmony_ci			ret = do_write(ff, &c->v, sizeof(u32));	\
11908c2ecf20Sopenharmony_ci			if (ret < 0)				\
11918c2ecf20Sopenharmony_ci				goto out;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci		_W(level)
11948c2ecf20Sopenharmony_ci		_W(line_size)
11958c2ecf20Sopenharmony_ci		_W(sets)
11968c2ecf20Sopenharmony_ci		_W(ways)
11978c2ecf20Sopenharmony_ci		#undef _W
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_ci		#define _W(v)						\
12008c2ecf20Sopenharmony_ci			ret = do_write_string(ff, (const char *) c->v);	\
12018c2ecf20Sopenharmony_ci			if (ret < 0)					\
12028c2ecf20Sopenharmony_ci				goto out;
12038c2ecf20Sopenharmony_ci
12048c2ecf20Sopenharmony_ci		_W(type)
12058c2ecf20Sopenharmony_ci		_W(size)
12068c2ecf20Sopenharmony_ci		_W(map)
12078c2ecf20Sopenharmony_ci		#undef _W
12088c2ecf20Sopenharmony_ci	}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ciout:
12118c2ecf20Sopenharmony_ci	for (i = 0; i < cnt; i++)
12128c2ecf20Sopenharmony_ci		cpu_cache_level__free(&caches[i]);
12138c2ecf20Sopenharmony_ci	return ret;
12148c2ecf20Sopenharmony_ci}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_cistatic int write_stat(struct feat_fd *ff __maybe_unused,
12178c2ecf20Sopenharmony_ci		      struct evlist *evlist __maybe_unused)
12188c2ecf20Sopenharmony_ci{
12198c2ecf20Sopenharmony_ci	return 0;
12208c2ecf20Sopenharmony_ci}
12218c2ecf20Sopenharmony_ci
12228c2ecf20Sopenharmony_cistatic int write_sample_time(struct feat_fd *ff,
12238c2ecf20Sopenharmony_ci			     struct evlist *evlist)
12248c2ecf20Sopenharmony_ci{
12258c2ecf20Sopenharmony_ci	int ret;
12268c2ecf20Sopenharmony_ci
12278c2ecf20Sopenharmony_ci	ret = do_write(ff, &evlist->first_sample_time,
12288c2ecf20Sopenharmony_ci		       sizeof(evlist->first_sample_time));
12298c2ecf20Sopenharmony_ci	if (ret < 0)
12308c2ecf20Sopenharmony_ci		return ret;
12318c2ecf20Sopenharmony_ci
12328c2ecf20Sopenharmony_ci	return do_write(ff, &evlist->last_sample_time,
12338c2ecf20Sopenharmony_ci			sizeof(evlist->last_sample_time));
12348c2ecf20Sopenharmony_ci}
12358c2ecf20Sopenharmony_ci
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_cistatic int memory_node__read(struct memory_node *n, unsigned long idx)
12388c2ecf20Sopenharmony_ci{
12398c2ecf20Sopenharmony_ci	unsigned int phys, size = 0;
12408c2ecf20Sopenharmony_ci	char path[PATH_MAX];
12418c2ecf20Sopenharmony_ci	struct dirent *ent;
12428c2ecf20Sopenharmony_ci	DIR *dir;
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci#define for_each_memory(mem, dir)					\
12458c2ecf20Sopenharmony_ci	while ((ent = readdir(dir)))					\
12468c2ecf20Sopenharmony_ci		if (strcmp(ent->d_name, ".") &&				\
12478c2ecf20Sopenharmony_ci		    strcmp(ent->d_name, "..") &&			\
12488c2ecf20Sopenharmony_ci		    sscanf(ent->d_name, "memory%u", &mem) == 1)
12498c2ecf20Sopenharmony_ci
12508c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX,
12518c2ecf20Sopenharmony_ci		  "%s/devices/system/node/node%lu",
12528c2ecf20Sopenharmony_ci		  sysfs__mountpoint(), idx);
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	dir = opendir(path);
12558c2ecf20Sopenharmony_ci	if (!dir) {
12568c2ecf20Sopenharmony_ci		pr_warning("failed: cant' open memory sysfs data\n");
12578c2ecf20Sopenharmony_ci		return -1;
12588c2ecf20Sopenharmony_ci	}
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	for_each_memory(phys, dir) {
12618c2ecf20Sopenharmony_ci		size = max(phys, size);
12628c2ecf20Sopenharmony_ci	}
12638c2ecf20Sopenharmony_ci
12648c2ecf20Sopenharmony_ci	size++;
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	n->set = bitmap_alloc(size);
12678c2ecf20Sopenharmony_ci	if (!n->set) {
12688c2ecf20Sopenharmony_ci		closedir(dir);
12698c2ecf20Sopenharmony_ci		return -ENOMEM;
12708c2ecf20Sopenharmony_ci	}
12718c2ecf20Sopenharmony_ci
12728c2ecf20Sopenharmony_ci	n->node = idx;
12738c2ecf20Sopenharmony_ci	n->size = size;
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci	rewinddir(dir);
12768c2ecf20Sopenharmony_ci
12778c2ecf20Sopenharmony_ci	for_each_memory(phys, dir) {
12788c2ecf20Sopenharmony_ci		set_bit(phys, n->set);
12798c2ecf20Sopenharmony_ci	}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	closedir(dir);
12828c2ecf20Sopenharmony_ci	return 0;
12838c2ecf20Sopenharmony_ci}
12848c2ecf20Sopenharmony_ci
12858c2ecf20Sopenharmony_cistatic int memory_node__sort(const void *a, const void *b)
12868c2ecf20Sopenharmony_ci{
12878c2ecf20Sopenharmony_ci	const struct memory_node *na = a;
12888c2ecf20Sopenharmony_ci	const struct memory_node *nb = b;
12898c2ecf20Sopenharmony_ci
12908c2ecf20Sopenharmony_ci	return na->node - nb->node;
12918c2ecf20Sopenharmony_ci}
12928c2ecf20Sopenharmony_ci
12938c2ecf20Sopenharmony_cistatic int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp)
12948c2ecf20Sopenharmony_ci{
12958c2ecf20Sopenharmony_ci	char path[PATH_MAX];
12968c2ecf20Sopenharmony_ci	struct dirent *ent;
12978c2ecf20Sopenharmony_ci	DIR *dir;
12988c2ecf20Sopenharmony_ci	u64 cnt = 0;
12998c2ecf20Sopenharmony_ci	int ret = 0;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/devices/system/node/",
13028c2ecf20Sopenharmony_ci		  sysfs__mountpoint());
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci	dir = opendir(path);
13058c2ecf20Sopenharmony_ci	if (!dir) {
13068c2ecf20Sopenharmony_ci		pr_debug2("%s: could't read %s, does this arch have topology information?\n",
13078c2ecf20Sopenharmony_ci			  __func__, path);
13088c2ecf20Sopenharmony_ci		return -1;
13098c2ecf20Sopenharmony_ci	}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci	while (!ret && (ent = readdir(dir))) {
13128c2ecf20Sopenharmony_ci		unsigned int idx;
13138c2ecf20Sopenharmony_ci		int r;
13148c2ecf20Sopenharmony_ci
13158c2ecf20Sopenharmony_ci		if (!strcmp(ent->d_name, ".") ||
13168c2ecf20Sopenharmony_ci		    !strcmp(ent->d_name, ".."))
13178c2ecf20Sopenharmony_ci			continue;
13188c2ecf20Sopenharmony_ci
13198c2ecf20Sopenharmony_ci		r = sscanf(ent->d_name, "node%u", &idx);
13208c2ecf20Sopenharmony_ci		if (r != 1)
13218c2ecf20Sopenharmony_ci			continue;
13228c2ecf20Sopenharmony_ci
13238c2ecf20Sopenharmony_ci		if (WARN_ONCE(cnt >= size,
13248c2ecf20Sopenharmony_ci			"failed to write MEM_TOPOLOGY, way too many nodes\n")) {
13258c2ecf20Sopenharmony_ci			closedir(dir);
13268c2ecf20Sopenharmony_ci			return -1;
13278c2ecf20Sopenharmony_ci		}
13288c2ecf20Sopenharmony_ci
13298c2ecf20Sopenharmony_ci		ret = memory_node__read(&nodes[cnt++], idx);
13308c2ecf20Sopenharmony_ci	}
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_ci	*cntp = cnt;
13338c2ecf20Sopenharmony_ci	closedir(dir);
13348c2ecf20Sopenharmony_ci
13358c2ecf20Sopenharmony_ci	if (!ret)
13368c2ecf20Sopenharmony_ci		qsort(nodes, cnt, sizeof(nodes[0]), memory_node__sort);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_ci	return ret;
13398c2ecf20Sopenharmony_ci}
13408c2ecf20Sopenharmony_ci
13418c2ecf20Sopenharmony_ci#define MAX_MEMORY_NODES 2000
13428c2ecf20Sopenharmony_ci
13438c2ecf20Sopenharmony_ci/*
13448c2ecf20Sopenharmony_ci * The MEM_TOPOLOGY holds physical memory map for every
13458c2ecf20Sopenharmony_ci * node in system. The format of data is as follows:
13468c2ecf20Sopenharmony_ci *
13478c2ecf20Sopenharmony_ci *  0 - version          | for future changes
13488c2ecf20Sopenharmony_ci *  8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes
13498c2ecf20Sopenharmony_ci * 16 - count            | number of nodes
13508c2ecf20Sopenharmony_ci *
13518c2ecf20Sopenharmony_ci * For each node we store map of physical indexes for
13528c2ecf20Sopenharmony_ci * each node:
13538c2ecf20Sopenharmony_ci *
13548c2ecf20Sopenharmony_ci * 32 - node id          | node index
13558c2ecf20Sopenharmony_ci * 40 - size             | size of bitmap
13568c2ecf20Sopenharmony_ci * 48 - bitmap           | bitmap of memory indexes that belongs to node
13578c2ecf20Sopenharmony_ci */
13588c2ecf20Sopenharmony_cistatic int write_mem_topology(struct feat_fd *ff __maybe_unused,
13598c2ecf20Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	static struct memory_node nodes[MAX_MEMORY_NODES];
13628c2ecf20Sopenharmony_ci	u64 bsize, version = 1, i, nr;
13638c2ecf20Sopenharmony_ci	int ret;
13648c2ecf20Sopenharmony_ci
13658c2ecf20Sopenharmony_ci	ret = sysfs__read_xll("devices/system/memory/block_size_bytes",
13668c2ecf20Sopenharmony_ci			      (unsigned long long *) &bsize);
13678c2ecf20Sopenharmony_ci	if (ret)
13688c2ecf20Sopenharmony_ci		return ret;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	ret = build_mem_topology(&nodes[0], MAX_MEMORY_NODES, &nr);
13718c2ecf20Sopenharmony_ci	if (ret)
13728c2ecf20Sopenharmony_ci		return ret;
13738c2ecf20Sopenharmony_ci
13748c2ecf20Sopenharmony_ci	ret = do_write(ff, &version, sizeof(version));
13758c2ecf20Sopenharmony_ci	if (ret < 0)
13768c2ecf20Sopenharmony_ci		goto out;
13778c2ecf20Sopenharmony_ci
13788c2ecf20Sopenharmony_ci	ret = do_write(ff, &bsize, sizeof(bsize));
13798c2ecf20Sopenharmony_ci	if (ret < 0)
13808c2ecf20Sopenharmony_ci		goto out;
13818c2ecf20Sopenharmony_ci
13828c2ecf20Sopenharmony_ci	ret = do_write(ff, &nr, sizeof(nr));
13838c2ecf20Sopenharmony_ci	if (ret < 0)
13848c2ecf20Sopenharmony_ci		goto out;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
13878c2ecf20Sopenharmony_ci		struct memory_node *n = &nodes[i];
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci		#define _W(v)						\
13908c2ecf20Sopenharmony_ci			ret = do_write(ff, &n->v, sizeof(n->v));	\
13918c2ecf20Sopenharmony_ci			if (ret < 0)					\
13928c2ecf20Sopenharmony_ci				goto out;
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ci		_W(node)
13958c2ecf20Sopenharmony_ci		_W(size)
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci		#undef _W
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci		ret = do_write_bitmap(ff, n->set, n->size);
14008c2ecf20Sopenharmony_ci		if (ret < 0)
14018c2ecf20Sopenharmony_ci			goto out;
14028c2ecf20Sopenharmony_ci	}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ciout:
14058c2ecf20Sopenharmony_ci	return ret;
14068c2ecf20Sopenharmony_ci}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_cistatic int write_compressed(struct feat_fd *ff __maybe_unused,
14098c2ecf20Sopenharmony_ci			    struct evlist *evlist __maybe_unused)
14108c2ecf20Sopenharmony_ci{
14118c2ecf20Sopenharmony_ci	int ret;
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_ver), sizeof(ff->ph->env.comp_ver));
14148c2ecf20Sopenharmony_ci	if (ret)
14158c2ecf20Sopenharmony_ci		return ret;
14168c2ecf20Sopenharmony_ci
14178c2ecf20Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_type), sizeof(ff->ph->env.comp_type));
14188c2ecf20Sopenharmony_ci	if (ret)
14198c2ecf20Sopenharmony_ci		return ret;
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_level), sizeof(ff->ph->env.comp_level));
14228c2ecf20Sopenharmony_ci	if (ret)
14238c2ecf20Sopenharmony_ci		return ret;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_ratio), sizeof(ff->ph->env.comp_ratio));
14268c2ecf20Sopenharmony_ci	if (ret)
14278c2ecf20Sopenharmony_ci		return ret;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci	return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len));
14308c2ecf20Sopenharmony_ci}
14318c2ecf20Sopenharmony_ci
14328c2ecf20Sopenharmony_cistatic int write_cpu_pmu_caps(struct feat_fd *ff,
14338c2ecf20Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
14348c2ecf20Sopenharmony_ci{
14358c2ecf20Sopenharmony_ci	struct perf_pmu *cpu_pmu = perf_pmu__find("cpu");
14368c2ecf20Sopenharmony_ci	struct perf_pmu_caps *caps = NULL;
14378c2ecf20Sopenharmony_ci	int nr_caps;
14388c2ecf20Sopenharmony_ci	int ret;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	if (!cpu_pmu)
14418c2ecf20Sopenharmony_ci		return -ENOENT;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci	nr_caps = perf_pmu__caps_parse(cpu_pmu);
14448c2ecf20Sopenharmony_ci	if (nr_caps < 0)
14458c2ecf20Sopenharmony_ci		return nr_caps;
14468c2ecf20Sopenharmony_ci
14478c2ecf20Sopenharmony_ci	ret = do_write(ff, &nr_caps, sizeof(nr_caps));
14488c2ecf20Sopenharmony_ci	if (ret < 0)
14498c2ecf20Sopenharmony_ci		return ret;
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	list_for_each_entry(caps, &cpu_pmu->caps, list) {
14528c2ecf20Sopenharmony_ci		ret = do_write_string(ff, caps->name);
14538c2ecf20Sopenharmony_ci		if (ret < 0)
14548c2ecf20Sopenharmony_ci			return ret;
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		ret = do_write_string(ff, caps->value);
14578c2ecf20Sopenharmony_ci		if (ret < 0)
14588c2ecf20Sopenharmony_ci			return ret;
14598c2ecf20Sopenharmony_ci	}
14608c2ecf20Sopenharmony_ci
14618c2ecf20Sopenharmony_ci	return ret;
14628c2ecf20Sopenharmony_ci}
14638c2ecf20Sopenharmony_ci
14648c2ecf20Sopenharmony_cistatic void print_hostname(struct feat_fd *ff, FILE *fp)
14658c2ecf20Sopenharmony_ci{
14668c2ecf20Sopenharmony_ci	fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
14678c2ecf20Sopenharmony_ci}
14688c2ecf20Sopenharmony_ci
14698c2ecf20Sopenharmony_cistatic void print_osrelease(struct feat_fd *ff, FILE *fp)
14708c2ecf20Sopenharmony_ci{
14718c2ecf20Sopenharmony_ci	fprintf(fp, "# os release : %s\n", ff->ph->env.os_release);
14728c2ecf20Sopenharmony_ci}
14738c2ecf20Sopenharmony_ci
14748c2ecf20Sopenharmony_cistatic void print_arch(struct feat_fd *ff, FILE *fp)
14758c2ecf20Sopenharmony_ci{
14768c2ecf20Sopenharmony_ci	fprintf(fp, "# arch : %s\n", ff->ph->env.arch);
14778c2ecf20Sopenharmony_ci}
14788c2ecf20Sopenharmony_ci
14798c2ecf20Sopenharmony_cistatic void print_cpudesc(struct feat_fd *ff, FILE *fp)
14808c2ecf20Sopenharmony_ci{
14818c2ecf20Sopenharmony_ci	fprintf(fp, "# cpudesc : %s\n", ff->ph->env.cpu_desc);
14828c2ecf20Sopenharmony_ci}
14838c2ecf20Sopenharmony_ci
14848c2ecf20Sopenharmony_cistatic void print_nrcpus(struct feat_fd *ff, FILE *fp)
14858c2ecf20Sopenharmony_ci{
14868c2ecf20Sopenharmony_ci	fprintf(fp, "# nrcpus online : %u\n", ff->ph->env.nr_cpus_online);
14878c2ecf20Sopenharmony_ci	fprintf(fp, "# nrcpus avail : %u\n", ff->ph->env.nr_cpus_avail);
14888c2ecf20Sopenharmony_ci}
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_cistatic void print_version(struct feat_fd *ff, FILE *fp)
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	fprintf(fp, "# perf version : %s\n", ff->ph->env.version);
14938c2ecf20Sopenharmony_ci}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_cistatic void print_cmdline(struct feat_fd *ff, FILE *fp)
14968c2ecf20Sopenharmony_ci{
14978c2ecf20Sopenharmony_ci	int nr, i;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	nr = ff->ph->env.nr_cmdline;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	fprintf(fp, "# cmdline : ");
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
15048c2ecf20Sopenharmony_ci		char *argv_i = strdup(ff->ph->env.cmdline_argv[i]);
15058c2ecf20Sopenharmony_ci		if (!argv_i) {
15068c2ecf20Sopenharmony_ci			fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]);
15078c2ecf20Sopenharmony_ci		} else {
15088c2ecf20Sopenharmony_ci			char *mem = argv_i;
15098c2ecf20Sopenharmony_ci			do {
15108c2ecf20Sopenharmony_ci				char *quote = strchr(argv_i, '\'');
15118c2ecf20Sopenharmony_ci				if (!quote)
15128c2ecf20Sopenharmony_ci					break;
15138c2ecf20Sopenharmony_ci				*quote++ = '\0';
15148c2ecf20Sopenharmony_ci				fprintf(fp, "%s\\\'", argv_i);
15158c2ecf20Sopenharmony_ci				argv_i = quote;
15168c2ecf20Sopenharmony_ci			} while (1);
15178c2ecf20Sopenharmony_ci			fprintf(fp, "%s ", argv_i);
15188c2ecf20Sopenharmony_ci			free(mem);
15198c2ecf20Sopenharmony_ci		}
15208c2ecf20Sopenharmony_ci	}
15218c2ecf20Sopenharmony_ci	fputc('\n', fp);
15228c2ecf20Sopenharmony_ci}
15238c2ecf20Sopenharmony_ci
15248c2ecf20Sopenharmony_cistatic void print_cpu_topology(struct feat_fd *ff, FILE *fp)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	struct perf_header *ph = ff->ph;
15278c2ecf20Sopenharmony_ci	int cpu_nr = ph->env.nr_cpus_avail;
15288c2ecf20Sopenharmony_ci	int nr, i;
15298c2ecf20Sopenharmony_ci	char *str;
15308c2ecf20Sopenharmony_ci
15318c2ecf20Sopenharmony_ci	nr = ph->env.nr_sibling_cores;
15328c2ecf20Sopenharmony_ci	str = ph->env.sibling_cores;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
15358c2ecf20Sopenharmony_ci		fprintf(fp, "# sibling sockets : %s\n", str);
15368c2ecf20Sopenharmony_ci		str += strlen(str) + 1;
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	if (ph->env.nr_sibling_dies) {
15408c2ecf20Sopenharmony_ci		nr = ph->env.nr_sibling_dies;
15418c2ecf20Sopenharmony_ci		str = ph->env.sibling_dies;
15428c2ecf20Sopenharmony_ci
15438c2ecf20Sopenharmony_ci		for (i = 0; i < nr; i++) {
15448c2ecf20Sopenharmony_ci			fprintf(fp, "# sibling dies    : %s\n", str);
15458c2ecf20Sopenharmony_ci			str += strlen(str) + 1;
15468c2ecf20Sopenharmony_ci		}
15478c2ecf20Sopenharmony_ci	}
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	nr = ph->env.nr_sibling_threads;
15508c2ecf20Sopenharmony_ci	str = ph->env.sibling_threads;
15518c2ecf20Sopenharmony_ci
15528c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
15538c2ecf20Sopenharmony_ci		fprintf(fp, "# sibling threads : %s\n", str);
15548c2ecf20Sopenharmony_ci		str += strlen(str) + 1;
15558c2ecf20Sopenharmony_ci	}
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	if (ph->env.nr_sibling_dies) {
15588c2ecf20Sopenharmony_ci		if (ph->env.cpu != NULL) {
15598c2ecf20Sopenharmony_ci			for (i = 0; i < cpu_nr; i++)
15608c2ecf20Sopenharmony_ci				fprintf(fp, "# CPU %d: Core ID %d, "
15618c2ecf20Sopenharmony_ci					    "Die ID %d, Socket ID %d\n",
15628c2ecf20Sopenharmony_ci					    i, ph->env.cpu[i].core_id,
15638c2ecf20Sopenharmony_ci					    ph->env.cpu[i].die_id,
15648c2ecf20Sopenharmony_ci					    ph->env.cpu[i].socket_id);
15658c2ecf20Sopenharmony_ci		} else
15668c2ecf20Sopenharmony_ci			fprintf(fp, "# Core ID, Die ID and Socket ID "
15678c2ecf20Sopenharmony_ci				    "information is not available\n");
15688c2ecf20Sopenharmony_ci	} else {
15698c2ecf20Sopenharmony_ci		if (ph->env.cpu != NULL) {
15708c2ecf20Sopenharmony_ci			for (i = 0; i < cpu_nr; i++)
15718c2ecf20Sopenharmony_ci				fprintf(fp, "# CPU %d: Core ID %d, "
15728c2ecf20Sopenharmony_ci					    "Socket ID %d\n",
15738c2ecf20Sopenharmony_ci					    i, ph->env.cpu[i].core_id,
15748c2ecf20Sopenharmony_ci					    ph->env.cpu[i].socket_id);
15758c2ecf20Sopenharmony_ci		} else
15768c2ecf20Sopenharmony_ci			fprintf(fp, "# Core ID and Socket ID "
15778c2ecf20Sopenharmony_ci				    "information is not available\n");
15788c2ecf20Sopenharmony_ci	}
15798c2ecf20Sopenharmony_ci}
15808c2ecf20Sopenharmony_ci
15818c2ecf20Sopenharmony_cistatic void print_clockid(struct feat_fd *ff, FILE *fp)
15828c2ecf20Sopenharmony_ci{
15838c2ecf20Sopenharmony_ci	fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n",
15848c2ecf20Sopenharmony_ci		ff->ph->env.clock.clockid_res_ns * 1000);
15858c2ecf20Sopenharmony_ci}
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_cistatic void print_clock_data(struct feat_fd *ff, FILE *fp)
15888c2ecf20Sopenharmony_ci{
15898c2ecf20Sopenharmony_ci	struct timespec clockid_ns;
15908c2ecf20Sopenharmony_ci	char tstr[64], date[64];
15918c2ecf20Sopenharmony_ci	struct timeval tod_ns;
15928c2ecf20Sopenharmony_ci	clockid_t clockid;
15938c2ecf20Sopenharmony_ci	struct tm ltime;
15948c2ecf20Sopenharmony_ci	u64 ref;
15958c2ecf20Sopenharmony_ci
15968c2ecf20Sopenharmony_ci	if (!ff->ph->env.clock.enabled) {
15978c2ecf20Sopenharmony_ci		fprintf(fp, "# reference time disabled\n");
15988c2ecf20Sopenharmony_ci		return;
15998c2ecf20Sopenharmony_ci	}
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	/* Compute TOD time. */
16028c2ecf20Sopenharmony_ci	ref = ff->ph->env.clock.tod_ns;
16038c2ecf20Sopenharmony_ci	tod_ns.tv_sec = ref / NSEC_PER_SEC;
16048c2ecf20Sopenharmony_ci	ref -= tod_ns.tv_sec * NSEC_PER_SEC;
16058c2ecf20Sopenharmony_ci	tod_ns.tv_usec = ref / NSEC_PER_USEC;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci	/* Compute clockid time. */
16088c2ecf20Sopenharmony_ci	ref = ff->ph->env.clock.clockid_ns;
16098c2ecf20Sopenharmony_ci	clockid_ns.tv_sec = ref / NSEC_PER_SEC;
16108c2ecf20Sopenharmony_ci	ref -= clockid_ns.tv_sec * NSEC_PER_SEC;
16118c2ecf20Sopenharmony_ci	clockid_ns.tv_nsec = ref;
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	clockid = ff->ph->env.clock.clockid;
16148c2ecf20Sopenharmony_ci
16158c2ecf20Sopenharmony_ci	if (localtime_r(&tod_ns.tv_sec, &ltime) == NULL)
16168c2ecf20Sopenharmony_ci		snprintf(tstr, sizeof(tstr), "<error>");
16178c2ecf20Sopenharmony_ci	else {
16188c2ecf20Sopenharmony_ci		strftime(date, sizeof(date), "%F %T", &ltime);
16198c2ecf20Sopenharmony_ci		scnprintf(tstr, sizeof(tstr), "%s.%06d",
16208c2ecf20Sopenharmony_ci			  date, (int) tod_ns.tv_usec);
16218c2ecf20Sopenharmony_ci	}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_ci	fprintf(fp, "# clockid: %s (%u)\n", clockid_name(clockid), clockid);
16248c2ecf20Sopenharmony_ci	fprintf(fp, "# reference time: %s = %ld.%06d (TOD) = %ld.%09ld (%s)\n",
16258c2ecf20Sopenharmony_ci		    tstr, tod_ns.tv_sec, (int) tod_ns.tv_usec,
16268c2ecf20Sopenharmony_ci		    clockid_ns.tv_sec, clockid_ns.tv_nsec,
16278c2ecf20Sopenharmony_ci		    clockid_name(clockid));
16288c2ecf20Sopenharmony_ci}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_cistatic void print_dir_format(struct feat_fd *ff, FILE *fp)
16318c2ecf20Sopenharmony_ci{
16328c2ecf20Sopenharmony_ci	struct perf_session *session;
16338c2ecf20Sopenharmony_ci	struct perf_data *data;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
16368c2ecf20Sopenharmony_ci	data = session->data;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version);
16398c2ecf20Sopenharmony_ci}
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_cistatic void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
16428c2ecf20Sopenharmony_ci{
16438c2ecf20Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
16448c2ecf20Sopenharmony_ci	struct rb_root *root;
16458c2ecf20Sopenharmony_ci	struct rb_node *next;
16468c2ecf20Sopenharmony_ci
16478c2ecf20Sopenharmony_ci	down_read(&env->bpf_progs.lock);
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	root = &env->bpf_progs.infos;
16508c2ecf20Sopenharmony_ci	next = rb_first(root);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	while (next) {
16538c2ecf20Sopenharmony_ci		struct bpf_prog_info_node *node;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
16568c2ecf20Sopenharmony_ci		next = rb_next(&node->rb_node);
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci		__bpf_event__print_bpf_prog_info(&node->info_linear->info,
16598c2ecf20Sopenharmony_ci						 env, fp);
16608c2ecf20Sopenharmony_ci	}
16618c2ecf20Sopenharmony_ci
16628c2ecf20Sopenharmony_ci	up_read(&env->bpf_progs.lock);
16638c2ecf20Sopenharmony_ci}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_cistatic void print_bpf_btf(struct feat_fd *ff, FILE *fp)
16668c2ecf20Sopenharmony_ci{
16678c2ecf20Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
16688c2ecf20Sopenharmony_ci	struct rb_root *root;
16698c2ecf20Sopenharmony_ci	struct rb_node *next;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci	down_read(&env->bpf_progs.lock);
16728c2ecf20Sopenharmony_ci
16738c2ecf20Sopenharmony_ci	root = &env->bpf_progs.btfs;
16748c2ecf20Sopenharmony_ci	next = rb_first(root);
16758c2ecf20Sopenharmony_ci
16768c2ecf20Sopenharmony_ci	while (next) {
16778c2ecf20Sopenharmony_ci		struct btf_node *node;
16788c2ecf20Sopenharmony_ci
16798c2ecf20Sopenharmony_ci		node = rb_entry(next, struct btf_node, rb_node);
16808c2ecf20Sopenharmony_ci		next = rb_next(&node->rb_node);
16818c2ecf20Sopenharmony_ci		fprintf(fp, "# btf info of id %u\n", node->id);
16828c2ecf20Sopenharmony_ci	}
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_ci	up_read(&env->bpf_progs.lock);
16858c2ecf20Sopenharmony_ci}
16868c2ecf20Sopenharmony_ci
16878c2ecf20Sopenharmony_cistatic void free_event_desc(struct evsel *events)
16888c2ecf20Sopenharmony_ci{
16898c2ecf20Sopenharmony_ci	struct evsel *evsel;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci	if (!events)
16928c2ecf20Sopenharmony_ci		return;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci	for (evsel = events; evsel->core.attr.size; evsel++) {
16958c2ecf20Sopenharmony_ci		zfree(&evsel->name);
16968c2ecf20Sopenharmony_ci		zfree(&evsel->core.id);
16978c2ecf20Sopenharmony_ci	}
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci	free(events);
17008c2ecf20Sopenharmony_ci}
17018c2ecf20Sopenharmony_ci
17028c2ecf20Sopenharmony_cistatic bool perf_attr_check(struct perf_event_attr *attr)
17038c2ecf20Sopenharmony_ci{
17048c2ecf20Sopenharmony_ci	if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) {
17058c2ecf20Sopenharmony_ci		pr_warning("Reserved bits are set unexpectedly. "
17068c2ecf20Sopenharmony_ci			   "Please update perf tool.\n");
17078c2ecf20Sopenharmony_ci		return false;
17088c2ecf20Sopenharmony_ci	}
17098c2ecf20Sopenharmony_ci
17108c2ecf20Sopenharmony_ci	if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) {
17118c2ecf20Sopenharmony_ci		pr_warning("Unknown sample type (0x%llx) is detected. "
17128c2ecf20Sopenharmony_ci			   "Please update perf tool.\n",
17138c2ecf20Sopenharmony_ci			   attr->sample_type);
17148c2ecf20Sopenharmony_ci		return false;
17158c2ecf20Sopenharmony_ci	}
17168c2ecf20Sopenharmony_ci
17178c2ecf20Sopenharmony_ci	if (attr->read_format & ~(PERF_FORMAT_MAX-1)) {
17188c2ecf20Sopenharmony_ci		pr_warning("Unknown read format (0x%llx) is detected. "
17198c2ecf20Sopenharmony_ci			   "Please update perf tool.\n",
17208c2ecf20Sopenharmony_ci			   attr->read_format);
17218c2ecf20Sopenharmony_ci		return false;
17228c2ecf20Sopenharmony_ci	}
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci	if ((attr->sample_type & PERF_SAMPLE_BRANCH_STACK) &&
17258c2ecf20Sopenharmony_ci	    (attr->branch_sample_type & ~(PERF_SAMPLE_BRANCH_MAX-1))) {
17268c2ecf20Sopenharmony_ci		pr_warning("Unknown branch sample type (0x%llx) is detected. "
17278c2ecf20Sopenharmony_ci			   "Please update perf tool.\n",
17288c2ecf20Sopenharmony_ci			   attr->branch_sample_type);
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci		return false;
17318c2ecf20Sopenharmony_ci	}
17328c2ecf20Sopenharmony_ci
17338c2ecf20Sopenharmony_ci	return true;
17348c2ecf20Sopenharmony_ci}
17358c2ecf20Sopenharmony_ci
17368c2ecf20Sopenharmony_cistatic struct evsel *read_event_desc(struct feat_fd *ff)
17378c2ecf20Sopenharmony_ci{
17388c2ecf20Sopenharmony_ci	struct evsel *evsel, *events = NULL;
17398c2ecf20Sopenharmony_ci	u64 *id;
17408c2ecf20Sopenharmony_ci	void *buf = NULL;
17418c2ecf20Sopenharmony_ci	u32 nre, sz, nr, i, j;
17428c2ecf20Sopenharmony_ci	size_t msz;
17438c2ecf20Sopenharmony_ci
17448c2ecf20Sopenharmony_ci	/* number of events */
17458c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nre))
17468c2ecf20Sopenharmony_ci		goto error;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &sz))
17498c2ecf20Sopenharmony_ci		goto error;
17508c2ecf20Sopenharmony_ci
17518c2ecf20Sopenharmony_ci	/* buffer to hold on file attr struct */
17528c2ecf20Sopenharmony_ci	buf = malloc(sz);
17538c2ecf20Sopenharmony_ci	if (!buf)
17548c2ecf20Sopenharmony_ci		goto error;
17558c2ecf20Sopenharmony_ci
17568c2ecf20Sopenharmony_ci	/* the last event terminates with evsel->core.attr.size == 0: */
17578c2ecf20Sopenharmony_ci	events = calloc(nre + 1, sizeof(*events));
17588c2ecf20Sopenharmony_ci	if (!events)
17598c2ecf20Sopenharmony_ci		goto error;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	msz = sizeof(evsel->core.attr);
17628c2ecf20Sopenharmony_ci	if (sz < msz)
17638c2ecf20Sopenharmony_ci		msz = sz;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	for (i = 0, evsel = events; i < nre; evsel++, i++) {
17668c2ecf20Sopenharmony_ci		evsel->idx = i;
17678c2ecf20Sopenharmony_ci
17688c2ecf20Sopenharmony_ci		/*
17698c2ecf20Sopenharmony_ci		 * must read entire on-file attr struct to
17708c2ecf20Sopenharmony_ci		 * sync up with layout.
17718c2ecf20Sopenharmony_ci		 */
17728c2ecf20Sopenharmony_ci		if (__do_read(ff, buf, sz))
17738c2ecf20Sopenharmony_ci			goto error;
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci		if (ff->ph->needs_swap)
17768c2ecf20Sopenharmony_ci			perf_event__attr_swap(buf);
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci		memcpy(&evsel->core.attr, buf, msz);
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci		if (!perf_attr_check(&evsel->core.attr))
17818c2ecf20Sopenharmony_ci			goto error;
17828c2ecf20Sopenharmony_ci
17838c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &nr))
17848c2ecf20Sopenharmony_ci			goto error;
17858c2ecf20Sopenharmony_ci
17868c2ecf20Sopenharmony_ci		if (ff->ph->needs_swap)
17878c2ecf20Sopenharmony_ci			evsel->needs_swap = true;
17888c2ecf20Sopenharmony_ci
17898c2ecf20Sopenharmony_ci		evsel->name = do_read_string(ff);
17908c2ecf20Sopenharmony_ci		if (!evsel->name)
17918c2ecf20Sopenharmony_ci			goto error;
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci		if (!nr)
17948c2ecf20Sopenharmony_ci			continue;
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci		id = calloc(nr, sizeof(*id));
17978c2ecf20Sopenharmony_ci		if (!id)
17988c2ecf20Sopenharmony_ci			goto error;
17998c2ecf20Sopenharmony_ci		evsel->core.ids = nr;
18008c2ecf20Sopenharmony_ci		evsel->core.id = id;
18018c2ecf20Sopenharmony_ci
18028c2ecf20Sopenharmony_ci		for (j = 0 ; j < nr; j++) {
18038c2ecf20Sopenharmony_ci			if (do_read_u64(ff, id))
18048c2ecf20Sopenharmony_ci				goto error;
18058c2ecf20Sopenharmony_ci			id++;
18068c2ecf20Sopenharmony_ci		}
18078c2ecf20Sopenharmony_ci	}
18088c2ecf20Sopenharmony_ciout:
18098c2ecf20Sopenharmony_ci	free(buf);
18108c2ecf20Sopenharmony_ci	return events;
18118c2ecf20Sopenharmony_cierror:
18128c2ecf20Sopenharmony_ci	free_event_desc(events);
18138c2ecf20Sopenharmony_ci	events = NULL;
18148c2ecf20Sopenharmony_ci	goto out;
18158c2ecf20Sopenharmony_ci}
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_cistatic int __desc_attr__fprintf(FILE *fp, const char *name, const char *val,
18188c2ecf20Sopenharmony_ci				void *priv __maybe_unused)
18198c2ecf20Sopenharmony_ci{
18208c2ecf20Sopenharmony_ci	return fprintf(fp, ", %s = %s", name, val);
18218c2ecf20Sopenharmony_ci}
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_cistatic void print_event_desc(struct feat_fd *ff, FILE *fp)
18248c2ecf20Sopenharmony_ci{
18258c2ecf20Sopenharmony_ci	struct evsel *evsel, *events;
18268c2ecf20Sopenharmony_ci	u32 j;
18278c2ecf20Sopenharmony_ci	u64 *id;
18288c2ecf20Sopenharmony_ci
18298c2ecf20Sopenharmony_ci	if (ff->events)
18308c2ecf20Sopenharmony_ci		events = ff->events;
18318c2ecf20Sopenharmony_ci	else
18328c2ecf20Sopenharmony_ci		events = read_event_desc(ff);
18338c2ecf20Sopenharmony_ci
18348c2ecf20Sopenharmony_ci	if (!events) {
18358c2ecf20Sopenharmony_ci		fprintf(fp, "# event desc: not available or unable to read\n");
18368c2ecf20Sopenharmony_ci		return;
18378c2ecf20Sopenharmony_ci	}
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	for (evsel = events; evsel->core.attr.size; evsel++) {
18408c2ecf20Sopenharmony_ci		fprintf(fp, "# event : name = %s, ", evsel->name);
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci		if (evsel->core.ids) {
18438c2ecf20Sopenharmony_ci			fprintf(fp, ", id = {");
18448c2ecf20Sopenharmony_ci			for (j = 0, id = evsel->core.id; j < evsel->core.ids; j++, id++) {
18458c2ecf20Sopenharmony_ci				if (j)
18468c2ecf20Sopenharmony_ci					fputc(',', fp);
18478c2ecf20Sopenharmony_ci				fprintf(fp, " %"PRIu64, *id);
18488c2ecf20Sopenharmony_ci			}
18498c2ecf20Sopenharmony_ci			fprintf(fp, " }");
18508c2ecf20Sopenharmony_ci		}
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci		perf_event_attr__fprintf(fp, &evsel->core.attr, __desc_attr__fprintf, NULL);
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci		fputc('\n', fp);
18558c2ecf20Sopenharmony_ci	}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	free_event_desc(events);
18588c2ecf20Sopenharmony_ci	ff->events = NULL;
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cistatic void print_total_mem(struct feat_fd *ff, FILE *fp)
18628c2ecf20Sopenharmony_ci{
18638c2ecf20Sopenharmony_ci	fprintf(fp, "# total memory : %llu kB\n", ff->ph->env.total_mem);
18648c2ecf20Sopenharmony_ci}
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_cistatic void print_numa_topology(struct feat_fd *ff, FILE *fp)
18678c2ecf20Sopenharmony_ci{
18688c2ecf20Sopenharmony_ci	int i;
18698c2ecf20Sopenharmony_ci	struct numa_node *n;
18708c2ecf20Sopenharmony_ci
18718c2ecf20Sopenharmony_ci	for (i = 0; i < ff->ph->env.nr_numa_nodes; i++) {
18728c2ecf20Sopenharmony_ci		n = &ff->ph->env.numa_nodes[i];
18738c2ecf20Sopenharmony_ci
18748c2ecf20Sopenharmony_ci		fprintf(fp, "# node%u meminfo  : total = %"PRIu64" kB,"
18758c2ecf20Sopenharmony_ci			    " free = %"PRIu64" kB\n",
18768c2ecf20Sopenharmony_ci			n->node, n->mem_total, n->mem_free);
18778c2ecf20Sopenharmony_ci
18788c2ecf20Sopenharmony_ci		fprintf(fp, "# node%u cpu list : ", n->node);
18798c2ecf20Sopenharmony_ci		cpu_map__fprintf(n->map, fp);
18808c2ecf20Sopenharmony_ci	}
18818c2ecf20Sopenharmony_ci}
18828c2ecf20Sopenharmony_ci
18838c2ecf20Sopenharmony_cistatic void print_cpuid(struct feat_fd *ff, FILE *fp)
18848c2ecf20Sopenharmony_ci{
18858c2ecf20Sopenharmony_ci	fprintf(fp, "# cpuid : %s\n", ff->ph->env.cpuid);
18868c2ecf20Sopenharmony_ci}
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_cistatic void print_branch_stack(struct feat_fd *ff __maybe_unused, FILE *fp)
18898c2ecf20Sopenharmony_ci{
18908c2ecf20Sopenharmony_ci	fprintf(fp, "# contains samples with branch stack\n");
18918c2ecf20Sopenharmony_ci}
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_cistatic void print_auxtrace(struct feat_fd *ff __maybe_unused, FILE *fp)
18948c2ecf20Sopenharmony_ci{
18958c2ecf20Sopenharmony_ci	fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
18968c2ecf20Sopenharmony_ci}
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_cistatic void print_stat(struct feat_fd *ff __maybe_unused, FILE *fp)
18998c2ecf20Sopenharmony_ci{
19008c2ecf20Sopenharmony_ci	fprintf(fp, "# contains stat data\n");
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_cistatic void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused)
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	int i;
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	fprintf(fp, "# CPU cache info:\n");
19088c2ecf20Sopenharmony_ci	for (i = 0; i < ff->ph->env.caches_cnt; i++) {
19098c2ecf20Sopenharmony_ci		fprintf(fp, "#  ");
19108c2ecf20Sopenharmony_ci		cpu_cache_level__fprintf(fp, &ff->ph->env.caches[i]);
19118c2ecf20Sopenharmony_ci	}
19128c2ecf20Sopenharmony_ci}
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_cistatic void print_compressed(struct feat_fd *ff, FILE *fp)
19158c2ecf20Sopenharmony_ci{
19168c2ecf20Sopenharmony_ci	fprintf(fp, "# compressed : %s, level = %d, ratio = %d\n",
19178c2ecf20Sopenharmony_ci		ff->ph->env.comp_type == PERF_COMP_ZSTD ? "Zstd" : "Unknown",
19188c2ecf20Sopenharmony_ci		ff->ph->env.comp_level, ff->ph->env.comp_ratio);
19198c2ecf20Sopenharmony_ci}
19208c2ecf20Sopenharmony_ci
19218c2ecf20Sopenharmony_cistatic void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
19228c2ecf20Sopenharmony_ci{
19238c2ecf20Sopenharmony_ci	const char *delimiter = "# cpu pmu capabilities: ";
19248c2ecf20Sopenharmony_ci	u32 nr_caps = ff->ph->env.nr_cpu_pmu_caps;
19258c2ecf20Sopenharmony_ci	char *str;
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_ci	if (!nr_caps) {
19288c2ecf20Sopenharmony_ci		fprintf(fp, "# cpu pmu capabilities: not available\n");
19298c2ecf20Sopenharmony_ci		return;
19308c2ecf20Sopenharmony_ci	}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_ci	str = ff->ph->env.cpu_pmu_caps;
19338c2ecf20Sopenharmony_ci	while (nr_caps--) {
19348c2ecf20Sopenharmony_ci		fprintf(fp, "%s%s", delimiter, str);
19358c2ecf20Sopenharmony_ci		delimiter = ", ";
19368c2ecf20Sopenharmony_ci		str += strlen(str) + 1;
19378c2ecf20Sopenharmony_ci	}
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	fprintf(fp, "\n");
19408c2ecf20Sopenharmony_ci}
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_cistatic void print_pmu_mappings(struct feat_fd *ff, FILE *fp)
19438c2ecf20Sopenharmony_ci{
19448c2ecf20Sopenharmony_ci	const char *delimiter = "# pmu mappings: ";
19458c2ecf20Sopenharmony_ci	char *str, *tmp;
19468c2ecf20Sopenharmony_ci	u32 pmu_num;
19478c2ecf20Sopenharmony_ci	u32 type;
19488c2ecf20Sopenharmony_ci
19498c2ecf20Sopenharmony_ci	pmu_num = ff->ph->env.nr_pmu_mappings;
19508c2ecf20Sopenharmony_ci	if (!pmu_num) {
19518c2ecf20Sopenharmony_ci		fprintf(fp, "# pmu mappings: not available\n");
19528c2ecf20Sopenharmony_ci		return;
19538c2ecf20Sopenharmony_ci	}
19548c2ecf20Sopenharmony_ci
19558c2ecf20Sopenharmony_ci	str = ff->ph->env.pmu_mappings;
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	while (pmu_num) {
19588c2ecf20Sopenharmony_ci		type = strtoul(str, &tmp, 0);
19598c2ecf20Sopenharmony_ci		if (*tmp != ':')
19608c2ecf20Sopenharmony_ci			goto error;
19618c2ecf20Sopenharmony_ci
19628c2ecf20Sopenharmony_ci		str = tmp + 1;
19638c2ecf20Sopenharmony_ci		fprintf(fp, "%s%s = %" PRIu32, delimiter, str, type);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci		delimiter = ", ";
19668c2ecf20Sopenharmony_ci		str += strlen(str) + 1;
19678c2ecf20Sopenharmony_ci		pmu_num--;
19688c2ecf20Sopenharmony_ci	}
19698c2ecf20Sopenharmony_ci
19708c2ecf20Sopenharmony_ci	fprintf(fp, "\n");
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci	if (!pmu_num)
19738c2ecf20Sopenharmony_ci		return;
19748c2ecf20Sopenharmony_cierror:
19758c2ecf20Sopenharmony_ci	fprintf(fp, "# pmu mappings: unable to read\n");
19768c2ecf20Sopenharmony_ci}
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_cistatic void print_group_desc(struct feat_fd *ff, FILE *fp)
19798c2ecf20Sopenharmony_ci{
19808c2ecf20Sopenharmony_ci	struct perf_session *session;
19818c2ecf20Sopenharmony_ci	struct evsel *evsel;
19828c2ecf20Sopenharmony_ci	u32 nr = 0;
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
19858c2ecf20Sopenharmony_ci
19868c2ecf20Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
19878c2ecf20Sopenharmony_ci		if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) {
19888c2ecf20Sopenharmony_ci			fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", evsel__name(evsel));
19898c2ecf20Sopenharmony_ci
19908c2ecf20Sopenharmony_ci			nr = evsel->core.nr_members - 1;
19918c2ecf20Sopenharmony_ci		} else if (nr) {
19928c2ecf20Sopenharmony_ci			fprintf(fp, ",%s", evsel__name(evsel));
19938c2ecf20Sopenharmony_ci
19948c2ecf20Sopenharmony_ci			if (--nr == 0)
19958c2ecf20Sopenharmony_ci				fprintf(fp, "}\n");
19968c2ecf20Sopenharmony_ci		}
19978c2ecf20Sopenharmony_ci	}
19988c2ecf20Sopenharmony_ci}
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_cistatic void print_sample_time(struct feat_fd *ff, FILE *fp)
20018c2ecf20Sopenharmony_ci{
20028c2ecf20Sopenharmony_ci	struct perf_session *session;
20038c2ecf20Sopenharmony_ci	char time_buf[32];
20048c2ecf20Sopenharmony_ci	double d;
20058c2ecf20Sopenharmony_ci
20068c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(session->evlist->first_sample_time,
20098c2ecf20Sopenharmony_ci				  time_buf, sizeof(time_buf));
20108c2ecf20Sopenharmony_ci	fprintf(fp, "# time of first sample : %s\n", time_buf);
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	timestamp__scnprintf_usec(session->evlist->last_sample_time,
20138c2ecf20Sopenharmony_ci				  time_buf, sizeof(time_buf));
20148c2ecf20Sopenharmony_ci	fprintf(fp, "# time of last sample : %s\n", time_buf);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	d = (double)(session->evlist->last_sample_time -
20178c2ecf20Sopenharmony_ci		session->evlist->first_sample_time) / NSEC_PER_MSEC;
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_ci	fprintf(fp, "# sample duration : %10.3f ms\n", d);
20208c2ecf20Sopenharmony_ci}
20218c2ecf20Sopenharmony_ci
20228c2ecf20Sopenharmony_cistatic void memory_node__fprintf(struct memory_node *n,
20238c2ecf20Sopenharmony_ci				 unsigned long long bsize, FILE *fp)
20248c2ecf20Sopenharmony_ci{
20258c2ecf20Sopenharmony_ci	char buf_map[100], buf_size[50];
20268c2ecf20Sopenharmony_ci	unsigned long long size;
20278c2ecf20Sopenharmony_ci
20288c2ecf20Sopenharmony_ci	size = bsize * bitmap_weight(n->set, n->size);
20298c2ecf20Sopenharmony_ci	unit_number__scnprintf(buf_size, 50, size);
20308c2ecf20Sopenharmony_ci
20318c2ecf20Sopenharmony_ci	bitmap_scnprintf(n->set, n->size, buf_map, 100);
20328c2ecf20Sopenharmony_ci	fprintf(fp, "#  %3" PRIu64 " [%s]: %s\n", n->node, buf_size, buf_map);
20338c2ecf20Sopenharmony_ci}
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_cistatic void print_mem_topology(struct feat_fd *ff, FILE *fp)
20368c2ecf20Sopenharmony_ci{
20378c2ecf20Sopenharmony_ci	struct memory_node *nodes;
20388c2ecf20Sopenharmony_ci	int i, nr;
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_ci	nodes = ff->ph->env.memory_nodes;
20418c2ecf20Sopenharmony_ci	nr    = ff->ph->env.nr_memory_nodes;
20428c2ecf20Sopenharmony_ci
20438c2ecf20Sopenharmony_ci	fprintf(fp, "# memory nodes (nr %d, block size 0x%llx):\n",
20448c2ecf20Sopenharmony_ci		nr, ff->ph->env.memory_bsize);
20458c2ecf20Sopenharmony_ci
20468c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
20478c2ecf20Sopenharmony_ci		memory_node__fprintf(&nodes[i], ff->ph->env.memory_bsize, fp);
20488c2ecf20Sopenharmony_ci	}
20498c2ecf20Sopenharmony_ci}
20508c2ecf20Sopenharmony_ci
20518c2ecf20Sopenharmony_cistatic int __event_process_build_id(struct perf_record_header_build_id *bev,
20528c2ecf20Sopenharmony_ci				    char *filename,
20538c2ecf20Sopenharmony_ci				    struct perf_session *session)
20548c2ecf20Sopenharmony_ci{
20558c2ecf20Sopenharmony_ci	int err = -1;
20568c2ecf20Sopenharmony_ci	struct machine *machine;
20578c2ecf20Sopenharmony_ci	u16 cpumode;
20588c2ecf20Sopenharmony_ci	struct dso *dso;
20598c2ecf20Sopenharmony_ci	enum dso_space_type dso_space;
20608c2ecf20Sopenharmony_ci
20618c2ecf20Sopenharmony_ci	machine = perf_session__findnew_machine(session, bev->pid);
20628c2ecf20Sopenharmony_ci	if (!machine)
20638c2ecf20Sopenharmony_ci		goto out;
20648c2ecf20Sopenharmony_ci
20658c2ecf20Sopenharmony_ci	cpumode = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	switch (cpumode) {
20688c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_KERNEL:
20698c2ecf20Sopenharmony_ci		dso_space = DSO_SPACE__KERNEL;
20708c2ecf20Sopenharmony_ci		break;
20718c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_KERNEL:
20728c2ecf20Sopenharmony_ci		dso_space = DSO_SPACE__KERNEL_GUEST;
20738c2ecf20Sopenharmony_ci		break;
20748c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_USER:
20758c2ecf20Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_USER:
20768c2ecf20Sopenharmony_ci		dso_space = DSO_SPACE__USER;
20778c2ecf20Sopenharmony_ci		break;
20788c2ecf20Sopenharmony_ci	default:
20798c2ecf20Sopenharmony_ci		goto out;
20808c2ecf20Sopenharmony_ci	}
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	dso = machine__findnew_dso(machine, filename);
20838c2ecf20Sopenharmony_ci	if (dso != NULL) {
20848c2ecf20Sopenharmony_ci		char sbuild_id[SBUILD_ID_SIZE];
20858c2ecf20Sopenharmony_ci		struct build_id bid;
20868c2ecf20Sopenharmony_ci		size_t size = BUILD_ID_SIZE;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci		if (bev->header.misc & PERF_RECORD_MISC_BUILD_ID_SIZE)
20898c2ecf20Sopenharmony_ci			size = bev->size;
20908c2ecf20Sopenharmony_ci
20918c2ecf20Sopenharmony_ci		build_id__init(&bid, bev->data, size);
20928c2ecf20Sopenharmony_ci		dso__set_build_id(dso, &bid);
20938c2ecf20Sopenharmony_ci
20948c2ecf20Sopenharmony_ci		if (dso_space != DSO_SPACE__USER) {
20958c2ecf20Sopenharmony_ci			struct kmod_path m = { .name = NULL, };
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci			if (!kmod_path__parse_name(&m, filename) && m.kmod)
20988c2ecf20Sopenharmony_ci				dso__set_module_info(dso, &m, machine);
20998c2ecf20Sopenharmony_ci
21008c2ecf20Sopenharmony_ci			dso->kernel = dso_space;
21018c2ecf20Sopenharmony_ci			free(m.name);
21028c2ecf20Sopenharmony_ci		}
21038c2ecf20Sopenharmony_ci
21048c2ecf20Sopenharmony_ci		build_id__sprintf(&dso->bid, sbuild_id);
21058c2ecf20Sopenharmony_ci		pr_debug("build id event received for %s: %s [%zu]\n",
21068c2ecf20Sopenharmony_ci			 dso->long_name, sbuild_id, size);
21078c2ecf20Sopenharmony_ci		dso__put(dso);
21088c2ecf20Sopenharmony_ci	}
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ci	err = 0;
21118c2ecf20Sopenharmony_ciout:
21128c2ecf20Sopenharmony_ci	return err;
21138c2ecf20Sopenharmony_ci}
21148c2ecf20Sopenharmony_ci
21158c2ecf20Sopenharmony_cistatic int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
21168c2ecf20Sopenharmony_ci						 int input, u64 offset, u64 size)
21178c2ecf20Sopenharmony_ci{
21188c2ecf20Sopenharmony_ci	struct perf_session *session = container_of(header, struct perf_session, header);
21198c2ecf20Sopenharmony_ci	struct {
21208c2ecf20Sopenharmony_ci		struct perf_event_header   header;
21218c2ecf20Sopenharmony_ci		u8			   build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))];
21228c2ecf20Sopenharmony_ci		char			   filename[0];
21238c2ecf20Sopenharmony_ci	} old_bev;
21248c2ecf20Sopenharmony_ci	struct perf_record_header_build_id bev;
21258c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
21268c2ecf20Sopenharmony_ci	u64 limit = offset + size;
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci	while (offset < limit) {
21298c2ecf20Sopenharmony_ci		ssize_t len;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci		if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
21328c2ecf20Sopenharmony_ci			return -1;
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_ci		if (header->needs_swap)
21358c2ecf20Sopenharmony_ci			perf_event_header__bswap(&old_bev.header);
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci		len = old_bev.header.size - sizeof(old_bev);
21388c2ecf20Sopenharmony_ci		if (readn(input, filename, len) != len)
21398c2ecf20Sopenharmony_ci			return -1;
21408c2ecf20Sopenharmony_ci
21418c2ecf20Sopenharmony_ci		bev.header = old_bev.header;
21428c2ecf20Sopenharmony_ci
21438c2ecf20Sopenharmony_ci		/*
21448c2ecf20Sopenharmony_ci		 * As the pid is the missing value, we need to fill
21458c2ecf20Sopenharmony_ci		 * it properly. The header.misc value give us nice hint.
21468c2ecf20Sopenharmony_ci		 */
21478c2ecf20Sopenharmony_ci		bev.pid	= HOST_KERNEL_ID;
21488c2ecf20Sopenharmony_ci		if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
21498c2ecf20Sopenharmony_ci		    bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
21508c2ecf20Sopenharmony_ci			bev.pid	= DEFAULT_GUEST_KERNEL_ID;
21518c2ecf20Sopenharmony_ci
21528c2ecf20Sopenharmony_ci		memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
21538c2ecf20Sopenharmony_ci		__event_process_build_id(&bev, filename, session);
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci		offset += bev.header.size;
21568c2ecf20Sopenharmony_ci	}
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci	return 0;
21598c2ecf20Sopenharmony_ci}
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_cistatic int perf_header__read_build_ids(struct perf_header *header,
21628c2ecf20Sopenharmony_ci				       int input, u64 offset, u64 size)
21638c2ecf20Sopenharmony_ci{
21648c2ecf20Sopenharmony_ci	struct perf_session *session = container_of(header, struct perf_session, header);
21658c2ecf20Sopenharmony_ci	struct perf_record_header_build_id bev;
21668c2ecf20Sopenharmony_ci	char filename[PATH_MAX];
21678c2ecf20Sopenharmony_ci	u64 limit = offset + size, orig_offset = offset;
21688c2ecf20Sopenharmony_ci	int err = -1;
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	while (offset < limit) {
21718c2ecf20Sopenharmony_ci		ssize_t len;
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ci		if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
21748c2ecf20Sopenharmony_ci			goto out;
21758c2ecf20Sopenharmony_ci
21768c2ecf20Sopenharmony_ci		if (header->needs_swap)
21778c2ecf20Sopenharmony_ci			perf_event_header__bswap(&bev.header);
21788c2ecf20Sopenharmony_ci
21798c2ecf20Sopenharmony_ci		len = bev.header.size - sizeof(bev);
21808c2ecf20Sopenharmony_ci		if (readn(input, filename, len) != len)
21818c2ecf20Sopenharmony_ci			goto out;
21828c2ecf20Sopenharmony_ci		/*
21838c2ecf20Sopenharmony_ci		 * The a1645ce1 changeset:
21848c2ecf20Sopenharmony_ci		 *
21858c2ecf20Sopenharmony_ci		 * "perf: 'perf kvm' tool for monitoring guest performance from host"
21868c2ecf20Sopenharmony_ci		 *
21878c2ecf20Sopenharmony_ci		 * Added a field to struct perf_record_header_build_id that broke the file
21888c2ecf20Sopenharmony_ci		 * format.
21898c2ecf20Sopenharmony_ci		 *
21908c2ecf20Sopenharmony_ci		 * Since the kernel build-id is the first entry, process the
21918c2ecf20Sopenharmony_ci		 * table using the old format if the well known
21928c2ecf20Sopenharmony_ci		 * '[kernel.kallsyms]' string for the kernel build-id has the
21938c2ecf20Sopenharmony_ci		 * first 4 characters chopped off (where the pid_t sits).
21948c2ecf20Sopenharmony_ci		 */
21958c2ecf20Sopenharmony_ci		if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
21968c2ecf20Sopenharmony_ci			if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
21978c2ecf20Sopenharmony_ci				return -1;
21988c2ecf20Sopenharmony_ci			return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
21998c2ecf20Sopenharmony_ci		}
22008c2ecf20Sopenharmony_ci
22018c2ecf20Sopenharmony_ci		__event_process_build_id(&bev, filename, session);
22028c2ecf20Sopenharmony_ci
22038c2ecf20Sopenharmony_ci		offset += bev.header.size;
22048c2ecf20Sopenharmony_ci	}
22058c2ecf20Sopenharmony_ci	err = 0;
22068c2ecf20Sopenharmony_ciout:
22078c2ecf20Sopenharmony_ci	return err;
22088c2ecf20Sopenharmony_ci}
22098c2ecf20Sopenharmony_ci
22108c2ecf20Sopenharmony_ci/* Macro for features that simply need to read and store a string. */
22118c2ecf20Sopenharmony_ci#define FEAT_PROCESS_STR_FUN(__feat, __feat_env) \
22128c2ecf20Sopenharmony_cistatic int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \
22138c2ecf20Sopenharmony_ci{\
22148c2ecf20Sopenharmony_ci	ff->ph->env.__feat_env = do_read_string(ff); \
22158c2ecf20Sopenharmony_ci	return ff->ph->env.__feat_env ? 0 : -ENOMEM; \
22168c2ecf20Sopenharmony_ci}
22178c2ecf20Sopenharmony_ci
22188c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(hostname, hostname);
22198c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(osrelease, os_release);
22208c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(version, version);
22218c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(arch, arch);
22228c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpudesc, cpu_desc);
22238c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpuid, cpuid);
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_cistatic int process_tracing_data(struct feat_fd *ff, void *data)
22268c2ecf20Sopenharmony_ci{
22278c2ecf20Sopenharmony_ci	ssize_t ret = trace_report(ff->fd, data, false);
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	return ret < 0 ? -1 : 0;
22308c2ecf20Sopenharmony_ci}
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_cistatic int process_build_id(struct feat_fd *ff, void *data __maybe_unused)
22338c2ecf20Sopenharmony_ci{
22348c2ecf20Sopenharmony_ci	if (perf_header__read_build_ids(ff->ph, ff->fd, ff->offset, ff->size))
22358c2ecf20Sopenharmony_ci		pr_debug("Failed to read buildids, continuing...\n");
22368c2ecf20Sopenharmony_ci	return 0;
22378c2ecf20Sopenharmony_ci}
22388c2ecf20Sopenharmony_ci
22398c2ecf20Sopenharmony_cistatic int process_nrcpus(struct feat_fd *ff, void *data __maybe_unused)
22408c2ecf20Sopenharmony_ci{
22418c2ecf20Sopenharmony_ci	int ret;
22428c2ecf20Sopenharmony_ci	u32 nr_cpus_avail, nr_cpus_online;
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	ret = do_read_u32(ff, &nr_cpus_avail);
22458c2ecf20Sopenharmony_ci	if (ret)
22468c2ecf20Sopenharmony_ci		return ret;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	ret = do_read_u32(ff, &nr_cpus_online);
22498c2ecf20Sopenharmony_ci	if (ret)
22508c2ecf20Sopenharmony_ci		return ret;
22518c2ecf20Sopenharmony_ci	ff->ph->env.nr_cpus_avail = (int)nr_cpus_avail;
22528c2ecf20Sopenharmony_ci	ff->ph->env.nr_cpus_online = (int)nr_cpus_online;
22538c2ecf20Sopenharmony_ci	return 0;
22548c2ecf20Sopenharmony_ci}
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_cistatic int process_total_mem(struct feat_fd *ff, void *data __maybe_unused)
22578c2ecf20Sopenharmony_ci{
22588c2ecf20Sopenharmony_ci	u64 total_mem;
22598c2ecf20Sopenharmony_ci	int ret;
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci	ret = do_read_u64(ff, &total_mem);
22628c2ecf20Sopenharmony_ci	if (ret)
22638c2ecf20Sopenharmony_ci		return -1;
22648c2ecf20Sopenharmony_ci	ff->ph->env.total_mem = (unsigned long long)total_mem;
22658c2ecf20Sopenharmony_ci	return 0;
22668c2ecf20Sopenharmony_ci}
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_cistatic struct evsel *
22698c2ecf20Sopenharmony_ciperf_evlist__find_by_index(struct evlist *evlist, int idx)
22708c2ecf20Sopenharmony_ci{
22718c2ecf20Sopenharmony_ci	struct evsel *evsel;
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
22748c2ecf20Sopenharmony_ci		if (evsel->idx == idx)
22758c2ecf20Sopenharmony_ci			return evsel;
22768c2ecf20Sopenharmony_ci	}
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	return NULL;
22798c2ecf20Sopenharmony_ci}
22808c2ecf20Sopenharmony_ci
22818c2ecf20Sopenharmony_cistatic void
22828c2ecf20Sopenharmony_ciperf_evlist__set_event_name(struct evlist *evlist,
22838c2ecf20Sopenharmony_ci			    struct evsel *event)
22848c2ecf20Sopenharmony_ci{
22858c2ecf20Sopenharmony_ci	struct evsel *evsel;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	if (!event->name)
22888c2ecf20Sopenharmony_ci		return;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	evsel = perf_evlist__find_by_index(evlist, event->idx);
22918c2ecf20Sopenharmony_ci	if (!evsel)
22928c2ecf20Sopenharmony_ci		return;
22938c2ecf20Sopenharmony_ci
22948c2ecf20Sopenharmony_ci	if (evsel->name)
22958c2ecf20Sopenharmony_ci		return;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci	evsel->name = strdup(event->name);
22988c2ecf20Sopenharmony_ci}
22998c2ecf20Sopenharmony_ci
23008c2ecf20Sopenharmony_cistatic int
23018c2ecf20Sopenharmony_ciprocess_event_desc(struct feat_fd *ff, void *data __maybe_unused)
23028c2ecf20Sopenharmony_ci{
23038c2ecf20Sopenharmony_ci	struct perf_session *session;
23048c2ecf20Sopenharmony_ci	struct evsel *evsel, *events = read_event_desc(ff);
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci	if (!events)
23078c2ecf20Sopenharmony_ci		return 0;
23088c2ecf20Sopenharmony_ci
23098c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
23108c2ecf20Sopenharmony_ci
23118c2ecf20Sopenharmony_ci	if (session->data->is_pipe) {
23128c2ecf20Sopenharmony_ci		/* Save events for reading later by print_event_desc,
23138c2ecf20Sopenharmony_ci		 * since they can't be read again in pipe mode. */
23148c2ecf20Sopenharmony_ci		ff->events = events;
23158c2ecf20Sopenharmony_ci	}
23168c2ecf20Sopenharmony_ci
23178c2ecf20Sopenharmony_ci	for (evsel = events; evsel->core.attr.size; evsel++)
23188c2ecf20Sopenharmony_ci		perf_evlist__set_event_name(session->evlist, evsel);
23198c2ecf20Sopenharmony_ci
23208c2ecf20Sopenharmony_ci	if (!session->data->is_pipe)
23218c2ecf20Sopenharmony_ci		free_event_desc(events);
23228c2ecf20Sopenharmony_ci
23238c2ecf20Sopenharmony_ci	return 0;
23248c2ecf20Sopenharmony_ci}
23258c2ecf20Sopenharmony_ci
23268c2ecf20Sopenharmony_cistatic int process_cmdline(struct feat_fd *ff, void *data __maybe_unused)
23278c2ecf20Sopenharmony_ci{
23288c2ecf20Sopenharmony_ci	char *str, *cmdline = NULL, **argv = NULL;
23298c2ecf20Sopenharmony_ci	u32 nr, i, len = 0;
23308c2ecf20Sopenharmony_ci
23318c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr))
23328c2ecf20Sopenharmony_ci		return -1;
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci	ff->ph->env.nr_cmdline = nr;
23358c2ecf20Sopenharmony_ci
23368c2ecf20Sopenharmony_ci	cmdline = zalloc(ff->size + nr + 1);
23378c2ecf20Sopenharmony_ci	if (!cmdline)
23388c2ecf20Sopenharmony_ci		return -1;
23398c2ecf20Sopenharmony_ci
23408c2ecf20Sopenharmony_ci	argv = zalloc(sizeof(char *) * (nr + 1));
23418c2ecf20Sopenharmony_ci	if (!argv)
23428c2ecf20Sopenharmony_ci		goto error;
23438c2ecf20Sopenharmony_ci
23448c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
23458c2ecf20Sopenharmony_ci		str = do_read_string(ff);
23468c2ecf20Sopenharmony_ci		if (!str)
23478c2ecf20Sopenharmony_ci			goto error;
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci		argv[i] = cmdline + len;
23508c2ecf20Sopenharmony_ci		memcpy(argv[i], str, strlen(str) + 1);
23518c2ecf20Sopenharmony_ci		len += strlen(str) + 1;
23528c2ecf20Sopenharmony_ci		free(str);
23538c2ecf20Sopenharmony_ci	}
23548c2ecf20Sopenharmony_ci	ff->ph->env.cmdline = cmdline;
23558c2ecf20Sopenharmony_ci	ff->ph->env.cmdline_argv = (const char **) argv;
23568c2ecf20Sopenharmony_ci	return 0;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_cierror:
23598c2ecf20Sopenharmony_ci	free(argv);
23608c2ecf20Sopenharmony_ci	free(cmdline);
23618c2ecf20Sopenharmony_ci	return -1;
23628c2ecf20Sopenharmony_ci}
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_cistatic int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
23658c2ecf20Sopenharmony_ci{
23668c2ecf20Sopenharmony_ci	u32 nr, i;
23678c2ecf20Sopenharmony_ci	char *str;
23688c2ecf20Sopenharmony_ci	struct strbuf sb;
23698c2ecf20Sopenharmony_ci	int cpu_nr = ff->ph->env.nr_cpus_avail;
23708c2ecf20Sopenharmony_ci	u64 size = 0;
23718c2ecf20Sopenharmony_ci	struct perf_header *ph = ff->ph;
23728c2ecf20Sopenharmony_ci	bool do_core_id_test = true;
23738c2ecf20Sopenharmony_ci
23748c2ecf20Sopenharmony_ci	ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu));
23758c2ecf20Sopenharmony_ci	if (!ph->env.cpu)
23768c2ecf20Sopenharmony_ci		return -1;
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr))
23798c2ecf20Sopenharmony_ci		goto free_cpu;
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_ci	ph->env.nr_sibling_cores = nr;
23828c2ecf20Sopenharmony_ci	size += sizeof(u32);
23838c2ecf20Sopenharmony_ci	if (strbuf_init(&sb, 128) < 0)
23848c2ecf20Sopenharmony_ci		goto free_cpu;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
23878c2ecf20Sopenharmony_ci		str = do_read_string(ff);
23888c2ecf20Sopenharmony_ci		if (!str)
23898c2ecf20Sopenharmony_ci			goto error;
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci		/* include a NULL character at the end */
23928c2ecf20Sopenharmony_ci		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
23938c2ecf20Sopenharmony_ci			goto error;
23948c2ecf20Sopenharmony_ci		size += string_size(str);
23958c2ecf20Sopenharmony_ci		free(str);
23968c2ecf20Sopenharmony_ci	}
23978c2ecf20Sopenharmony_ci	ph->env.sibling_cores = strbuf_detach(&sb, NULL);
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr))
24008c2ecf20Sopenharmony_ci		return -1;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	ph->env.nr_sibling_threads = nr;
24038c2ecf20Sopenharmony_ci	size += sizeof(u32);
24048c2ecf20Sopenharmony_ci
24058c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
24068c2ecf20Sopenharmony_ci		str = do_read_string(ff);
24078c2ecf20Sopenharmony_ci		if (!str)
24088c2ecf20Sopenharmony_ci			goto error;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci		/* include a NULL character at the end */
24118c2ecf20Sopenharmony_ci		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
24128c2ecf20Sopenharmony_ci			goto error;
24138c2ecf20Sopenharmony_ci		size += string_size(str);
24148c2ecf20Sopenharmony_ci		free(str);
24158c2ecf20Sopenharmony_ci	}
24168c2ecf20Sopenharmony_ci	ph->env.sibling_threads = strbuf_detach(&sb, NULL);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	/*
24198c2ecf20Sopenharmony_ci	 * The header may be from old perf,
24208c2ecf20Sopenharmony_ci	 * which doesn't include core id and socket id information.
24218c2ecf20Sopenharmony_ci	 */
24228c2ecf20Sopenharmony_ci	if (ff->size <= size) {
24238c2ecf20Sopenharmony_ci		zfree(&ph->env.cpu);
24248c2ecf20Sopenharmony_ci		return 0;
24258c2ecf20Sopenharmony_ci	}
24268c2ecf20Sopenharmony_ci
24278c2ecf20Sopenharmony_ci	/* On s390 the socket_id number is not related to the numbers of cpus.
24288c2ecf20Sopenharmony_ci	 * The socket_id number might be higher than the numbers of cpus.
24298c2ecf20Sopenharmony_ci	 * This depends on the configuration.
24308c2ecf20Sopenharmony_ci	 * AArch64 is the same.
24318c2ecf20Sopenharmony_ci	 */
24328c2ecf20Sopenharmony_ci	if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4)
24338c2ecf20Sopenharmony_ci			  || !strncmp(ph->env.arch, "aarch64", 7)))
24348c2ecf20Sopenharmony_ci		do_core_id_test = false;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	for (i = 0; i < (u32)cpu_nr; i++) {
24378c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &nr))
24388c2ecf20Sopenharmony_ci			goto free_cpu;
24398c2ecf20Sopenharmony_ci
24408c2ecf20Sopenharmony_ci		ph->env.cpu[i].core_id = nr;
24418c2ecf20Sopenharmony_ci		size += sizeof(u32);
24428c2ecf20Sopenharmony_ci
24438c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &nr))
24448c2ecf20Sopenharmony_ci			goto free_cpu;
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci		if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) {
24478c2ecf20Sopenharmony_ci			pr_debug("socket_id number is too big."
24488c2ecf20Sopenharmony_ci				 "You may need to upgrade the perf tool.\n");
24498c2ecf20Sopenharmony_ci			goto free_cpu;
24508c2ecf20Sopenharmony_ci		}
24518c2ecf20Sopenharmony_ci
24528c2ecf20Sopenharmony_ci		ph->env.cpu[i].socket_id = nr;
24538c2ecf20Sopenharmony_ci		size += sizeof(u32);
24548c2ecf20Sopenharmony_ci	}
24558c2ecf20Sopenharmony_ci
24568c2ecf20Sopenharmony_ci	/*
24578c2ecf20Sopenharmony_ci	 * The header may be from old perf,
24588c2ecf20Sopenharmony_ci	 * which doesn't include die information.
24598c2ecf20Sopenharmony_ci	 */
24608c2ecf20Sopenharmony_ci	if (ff->size <= size)
24618c2ecf20Sopenharmony_ci		return 0;
24628c2ecf20Sopenharmony_ci
24638c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr))
24648c2ecf20Sopenharmony_ci		return -1;
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	ph->env.nr_sibling_dies = nr;
24678c2ecf20Sopenharmony_ci	size += sizeof(u32);
24688c2ecf20Sopenharmony_ci
24698c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
24708c2ecf20Sopenharmony_ci		str = do_read_string(ff);
24718c2ecf20Sopenharmony_ci		if (!str)
24728c2ecf20Sopenharmony_ci			goto error;
24738c2ecf20Sopenharmony_ci
24748c2ecf20Sopenharmony_ci		/* include a NULL character at the end */
24758c2ecf20Sopenharmony_ci		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
24768c2ecf20Sopenharmony_ci			goto error;
24778c2ecf20Sopenharmony_ci		size += string_size(str);
24788c2ecf20Sopenharmony_ci		free(str);
24798c2ecf20Sopenharmony_ci	}
24808c2ecf20Sopenharmony_ci	ph->env.sibling_dies = strbuf_detach(&sb, NULL);
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci	for (i = 0; i < (u32)cpu_nr; i++) {
24838c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &nr))
24848c2ecf20Sopenharmony_ci			goto free_cpu;
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci		ph->env.cpu[i].die_id = nr;
24878c2ecf20Sopenharmony_ci	}
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	return 0;
24908c2ecf20Sopenharmony_ci
24918c2ecf20Sopenharmony_cierror:
24928c2ecf20Sopenharmony_ci	strbuf_release(&sb);
24938c2ecf20Sopenharmony_cifree_cpu:
24948c2ecf20Sopenharmony_ci	zfree(&ph->env.cpu);
24958c2ecf20Sopenharmony_ci	return -1;
24968c2ecf20Sopenharmony_ci}
24978c2ecf20Sopenharmony_ci
24988c2ecf20Sopenharmony_cistatic int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused)
24998c2ecf20Sopenharmony_ci{
25008c2ecf20Sopenharmony_ci	struct numa_node *nodes, *n;
25018c2ecf20Sopenharmony_ci	u32 nr, i;
25028c2ecf20Sopenharmony_ci	char *str;
25038c2ecf20Sopenharmony_ci
25048c2ecf20Sopenharmony_ci	/* nr nodes */
25058c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr))
25068c2ecf20Sopenharmony_ci		return -1;
25078c2ecf20Sopenharmony_ci
25088c2ecf20Sopenharmony_ci	nodes = zalloc(sizeof(*nodes) * nr);
25098c2ecf20Sopenharmony_ci	if (!nodes)
25108c2ecf20Sopenharmony_ci		return -ENOMEM;
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
25138c2ecf20Sopenharmony_ci		n = &nodes[i];
25148c2ecf20Sopenharmony_ci
25158c2ecf20Sopenharmony_ci		/* node number */
25168c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &n->node))
25178c2ecf20Sopenharmony_ci			goto error;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci		if (do_read_u64(ff, &n->mem_total))
25208c2ecf20Sopenharmony_ci			goto error;
25218c2ecf20Sopenharmony_ci
25228c2ecf20Sopenharmony_ci		if (do_read_u64(ff, &n->mem_free))
25238c2ecf20Sopenharmony_ci			goto error;
25248c2ecf20Sopenharmony_ci
25258c2ecf20Sopenharmony_ci		str = do_read_string(ff);
25268c2ecf20Sopenharmony_ci		if (!str)
25278c2ecf20Sopenharmony_ci			goto error;
25288c2ecf20Sopenharmony_ci
25298c2ecf20Sopenharmony_ci		n->map = perf_cpu_map__new(str);
25308c2ecf20Sopenharmony_ci		if (!n->map)
25318c2ecf20Sopenharmony_ci			goto error;
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci		free(str);
25348c2ecf20Sopenharmony_ci	}
25358c2ecf20Sopenharmony_ci	ff->ph->env.nr_numa_nodes = nr;
25368c2ecf20Sopenharmony_ci	ff->ph->env.numa_nodes = nodes;
25378c2ecf20Sopenharmony_ci	return 0;
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_cierror:
25408c2ecf20Sopenharmony_ci	free(nodes);
25418c2ecf20Sopenharmony_ci	return -1;
25428c2ecf20Sopenharmony_ci}
25438c2ecf20Sopenharmony_ci
25448c2ecf20Sopenharmony_cistatic int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused)
25458c2ecf20Sopenharmony_ci{
25468c2ecf20Sopenharmony_ci	char *name;
25478c2ecf20Sopenharmony_ci	u32 pmu_num;
25488c2ecf20Sopenharmony_ci	u32 type;
25498c2ecf20Sopenharmony_ci	struct strbuf sb;
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &pmu_num))
25528c2ecf20Sopenharmony_ci		return -1;
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci	if (!pmu_num) {
25558c2ecf20Sopenharmony_ci		pr_debug("pmu mappings not available\n");
25568c2ecf20Sopenharmony_ci		return 0;
25578c2ecf20Sopenharmony_ci	}
25588c2ecf20Sopenharmony_ci
25598c2ecf20Sopenharmony_ci	ff->ph->env.nr_pmu_mappings = pmu_num;
25608c2ecf20Sopenharmony_ci	if (strbuf_init(&sb, 128) < 0)
25618c2ecf20Sopenharmony_ci		return -1;
25628c2ecf20Sopenharmony_ci
25638c2ecf20Sopenharmony_ci	while (pmu_num) {
25648c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &type))
25658c2ecf20Sopenharmony_ci			goto error;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci		name = do_read_string(ff);
25688c2ecf20Sopenharmony_ci		if (!name)
25698c2ecf20Sopenharmony_ci			goto error;
25708c2ecf20Sopenharmony_ci
25718c2ecf20Sopenharmony_ci		if (strbuf_addf(&sb, "%u:%s", type, name) < 0)
25728c2ecf20Sopenharmony_ci			goto error;
25738c2ecf20Sopenharmony_ci		/* include a NULL character at the end */
25748c2ecf20Sopenharmony_ci		if (strbuf_add(&sb, "", 1) < 0)
25758c2ecf20Sopenharmony_ci			goto error;
25768c2ecf20Sopenharmony_ci
25778c2ecf20Sopenharmony_ci		if (!strcmp(name, "msr"))
25788c2ecf20Sopenharmony_ci			ff->ph->env.msr_pmu_type = type;
25798c2ecf20Sopenharmony_ci
25808c2ecf20Sopenharmony_ci		free(name);
25818c2ecf20Sopenharmony_ci		pmu_num--;
25828c2ecf20Sopenharmony_ci	}
25838c2ecf20Sopenharmony_ci	ff->ph->env.pmu_mappings = strbuf_detach(&sb, NULL);
25848c2ecf20Sopenharmony_ci	return 0;
25858c2ecf20Sopenharmony_ci
25868c2ecf20Sopenharmony_cierror:
25878c2ecf20Sopenharmony_ci	strbuf_release(&sb);
25888c2ecf20Sopenharmony_ci	return -1;
25898c2ecf20Sopenharmony_ci}
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_cistatic int process_group_desc(struct feat_fd *ff, void *data __maybe_unused)
25928c2ecf20Sopenharmony_ci{
25938c2ecf20Sopenharmony_ci	size_t ret = -1;
25948c2ecf20Sopenharmony_ci	u32 i, nr, nr_groups;
25958c2ecf20Sopenharmony_ci	struct perf_session *session;
25968c2ecf20Sopenharmony_ci	struct evsel *evsel, *leader = NULL;
25978c2ecf20Sopenharmony_ci	struct group_desc {
25988c2ecf20Sopenharmony_ci		char *name;
25998c2ecf20Sopenharmony_ci		u32 leader_idx;
26008c2ecf20Sopenharmony_ci		u32 nr_members;
26018c2ecf20Sopenharmony_ci	} *desc;
26028c2ecf20Sopenharmony_ci
26038c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr_groups))
26048c2ecf20Sopenharmony_ci		return -1;
26058c2ecf20Sopenharmony_ci
26068c2ecf20Sopenharmony_ci	ff->ph->env.nr_groups = nr_groups;
26078c2ecf20Sopenharmony_ci	if (!nr_groups) {
26088c2ecf20Sopenharmony_ci		pr_debug("group desc not available\n");
26098c2ecf20Sopenharmony_ci		return 0;
26108c2ecf20Sopenharmony_ci	}
26118c2ecf20Sopenharmony_ci
26128c2ecf20Sopenharmony_ci	desc = calloc(nr_groups, sizeof(*desc));
26138c2ecf20Sopenharmony_ci	if (!desc)
26148c2ecf20Sopenharmony_ci		return -1;
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci	for (i = 0; i < nr_groups; i++) {
26178c2ecf20Sopenharmony_ci		desc[i].name = do_read_string(ff);
26188c2ecf20Sopenharmony_ci		if (!desc[i].name)
26198c2ecf20Sopenharmony_ci			goto out_free;
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &desc[i].leader_idx))
26228c2ecf20Sopenharmony_ci			goto out_free;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &desc[i].nr_members))
26258c2ecf20Sopenharmony_ci			goto out_free;
26268c2ecf20Sopenharmony_ci	}
26278c2ecf20Sopenharmony_ci
26288c2ecf20Sopenharmony_ci	/*
26298c2ecf20Sopenharmony_ci	 * Rebuild group relationship based on the group_desc
26308c2ecf20Sopenharmony_ci	 */
26318c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
26328c2ecf20Sopenharmony_ci	session->evlist->nr_groups = nr_groups;
26338c2ecf20Sopenharmony_ci
26348c2ecf20Sopenharmony_ci	i = nr = 0;
26358c2ecf20Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
26368c2ecf20Sopenharmony_ci		if (evsel->idx == (int) desc[i].leader_idx) {
26378c2ecf20Sopenharmony_ci			evsel->leader = evsel;
26388c2ecf20Sopenharmony_ci			/* {anon_group} is a dummy name */
26398c2ecf20Sopenharmony_ci			if (strcmp(desc[i].name, "{anon_group}")) {
26408c2ecf20Sopenharmony_ci				evsel->group_name = desc[i].name;
26418c2ecf20Sopenharmony_ci				desc[i].name = NULL;
26428c2ecf20Sopenharmony_ci			}
26438c2ecf20Sopenharmony_ci			evsel->core.nr_members = desc[i].nr_members;
26448c2ecf20Sopenharmony_ci
26458c2ecf20Sopenharmony_ci			if (i >= nr_groups || nr > 0) {
26468c2ecf20Sopenharmony_ci				pr_debug("invalid group desc\n");
26478c2ecf20Sopenharmony_ci				goto out_free;
26488c2ecf20Sopenharmony_ci			}
26498c2ecf20Sopenharmony_ci
26508c2ecf20Sopenharmony_ci			leader = evsel;
26518c2ecf20Sopenharmony_ci			nr = evsel->core.nr_members - 1;
26528c2ecf20Sopenharmony_ci			i++;
26538c2ecf20Sopenharmony_ci		} else if (nr) {
26548c2ecf20Sopenharmony_ci			/* This is a group member */
26558c2ecf20Sopenharmony_ci			evsel->leader = leader;
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci			nr--;
26588c2ecf20Sopenharmony_ci		}
26598c2ecf20Sopenharmony_ci	}
26608c2ecf20Sopenharmony_ci
26618c2ecf20Sopenharmony_ci	if (i != nr_groups || nr != 0) {
26628c2ecf20Sopenharmony_ci		pr_debug("invalid group desc\n");
26638c2ecf20Sopenharmony_ci		goto out_free;
26648c2ecf20Sopenharmony_ci	}
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	ret = 0;
26678c2ecf20Sopenharmony_ciout_free:
26688c2ecf20Sopenharmony_ci	for (i = 0; i < nr_groups; i++)
26698c2ecf20Sopenharmony_ci		zfree(&desc[i].name);
26708c2ecf20Sopenharmony_ci	free(desc);
26718c2ecf20Sopenharmony_ci
26728c2ecf20Sopenharmony_ci	return ret;
26738c2ecf20Sopenharmony_ci}
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_cistatic int process_auxtrace(struct feat_fd *ff, void *data __maybe_unused)
26768c2ecf20Sopenharmony_ci{
26778c2ecf20Sopenharmony_ci	struct perf_session *session;
26788c2ecf20Sopenharmony_ci	int err;
26798c2ecf20Sopenharmony_ci
26808c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
26818c2ecf20Sopenharmony_ci
26828c2ecf20Sopenharmony_ci	err = auxtrace_index__process(ff->fd, ff->size, session,
26838c2ecf20Sopenharmony_ci				      ff->ph->needs_swap);
26848c2ecf20Sopenharmony_ci	if (err < 0)
26858c2ecf20Sopenharmony_ci		pr_err("Failed to process auxtrace index\n");
26868c2ecf20Sopenharmony_ci	return err;
26878c2ecf20Sopenharmony_ci}
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_cistatic int process_cache(struct feat_fd *ff, void *data __maybe_unused)
26908c2ecf20Sopenharmony_ci{
26918c2ecf20Sopenharmony_ci	struct cpu_cache_level *caches;
26928c2ecf20Sopenharmony_ci	u32 cnt, i, version;
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &version))
26958c2ecf20Sopenharmony_ci		return -1;
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci	if (version != 1)
26988c2ecf20Sopenharmony_ci		return -1;
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &cnt))
27018c2ecf20Sopenharmony_ci		return -1;
27028c2ecf20Sopenharmony_ci
27038c2ecf20Sopenharmony_ci	caches = zalloc(sizeof(*caches) * cnt);
27048c2ecf20Sopenharmony_ci	if (!caches)
27058c2ecf20Sopenharmony_ci		return -1;
27068c2ecf20Sopenharmony_ci
27078c2ecf20Sopenharmony_ci	for (i = 0; i < cnt; i++) {
27088c2ecf20Sopenharmony_ci		struct cpu_cache_level c;
27098c2ecf20Sopenharmony_ci
27108c2ecf20Sopenharmony_ci		#define _R(v)						\
27118c2ecf20Sopenharmony_ci			if (do_read_u32(ff, &c.v))\
27128c2ecf20Sopenharmony_ci				goto out_free_caches;			\
27138c2ecf20Sopenharmony_ci
27148c2ecf20Sopenharmony_ci		_R(level)
27158c2ecf20Sopenharmony_ci		_R(line_size)
27168c2ecf20Sopenharmony_ci		_R(sets)
27178c2ecf20Sopenharmony_ci		_R(ways)
27188c2ecf20Sopenharmony_ci		#undef _R
27198c2ecf20Sopenharmony_ci
27208c2ecf20Sopenharmony_ci		#define _R(v)					\
27218c2ecf20Sopenharmony_ci			c.v = do_read_string(ff);		\
27228c2ecf20Sopenharmony_ci			if (!c.v)				\
27238c2ecf20Sopenharmony_ci				goto out_free_caches;
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci		_R(type)
27268c2ecf20Sopenharmony_ci		_R(size)
27278c2ecf20Sopenharmony_ci		_R(map)
27288c2ecf20Sopenharmony_ci		#undef _R
27298c2ecf20Sopenharmony_ci
27308c2ecf20Sopenharmony_ci		caches[i] = c;
27318c2ecf20Sopenharmony_ci	}
27328c2ecf20Sopenharmony_ci
27338c2ecf20Sopenharmony_ci	ff->ph->env.caches = caches;
27348c2ecf20Sopenharmony_ci	ff->ph->env.caches_cnt = cnt;
27358c2ecf20Sopenharmony_ci	return 0;
27368c2ecf20Sopenharmony_ciout_free_caches:
27378c2ecf20Sopenharmony_ci	free(caches);
27388c2ecf20Sopenharmony_ci	return -1;
27398c2ecf20Sopenharmony_ci}
27408c2ecf20Sopenharmony_ci
27418c2ecf20Sopenharmony_cistatic int process_sample_time(struct feat_fd *ff, void *data __maybe_unused)
27428c2ecf20Sopenharmony_ci{
27438c2ecf20Sopenharmony_ci	struct perf_session *session;
27448c2ecf20Sopenharmony_ci	u64 first_sample_time, last_sample_time;
27458c2ecf20Sopenharmony_ci	int ret;
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci	ret = do_read_u64(ff, &first_sample_time);
27508c2ecf20Sopenharmony_ci	if (ret)
27518c2ecf20Sopenharmony_ci		return -1;
27528c2ecf20Sopenharmony_ci
27538c2ecf20Sopenharmony_ci	ret = do_read_u64(ff, &last_sample_time);
27548c2ecf20Sopenharmony_ci	if (ret)
27558c2ecf20Sopenharmony_ci		return -1;
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	session->evlist->first_sample_time = first_sample_time;
27588c2ecf20Sopenharmony_ci	session->evlist->last_sample_time = last_sample_time;
27598c2ecf20Sopenharmony_ci	return 0;
27608c2ecf20Sopenharmony_ci}
27618c2ecf20Sopenharmony_ci
27628c2ecf20Sopenharmony_cistatic int process_mem_topology(struct feat_fd *ff,
27638c2ecf20Sopenharmony_ci				void *data __maybe_unused)
27648c2ecf20Sopenharmony_ci{
27658c2ecf20Sopenharmony_ci	struct memory_node *nodes;
27668c2ecf20Sopenharmony_ci	u64 version, i, nr, bsize;
27678c2ecf20Sopenharmony_ci	int ret = -1;
27688c2ecf20Sopenharmony_ci
27698c2ecf20Sopenharmony_ci	if (do_read_u64(ff, &version))
27708c2ecf20Sopenharmony_ci		return -1;
27718c2ecf20Sopenharmony_ci
27728c2ecf20Sopenharmony_ci	if (version != 1)
27738c2ecf20Sopenharmony_ci		return -1;
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	if (do_read_u64(ff, &bsize))
27768c2ecf20Sopenharmony_ci		return -1;
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_ci	if (do_read_u64(ff, &nr))
27798c2ecf20Sopenharmony_ci		return -1;
27808c2ecf20Sopenharmony_ci
27818c2ecf20Sopenharmony_ci	nodes = zalloc(sizeof(*nodes) * nr);
27828c2ecf20Sopenharmony_ci	if (!nodes)
27838c2ecf20Sopenharmony_ci		return -1;
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci	for (i = 0; i < nr; i++) {
27868c2ecf20Sopenharmony_ci		struct memory_node n;
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci		#define _R(v)				\
27898c2ecf20Sopenharmony_ci			if (do_read_u64(ff, &n.v))	\
27908c2ecf20Sopenharmony_ci				goto out;		\
27918c2ecf20Sopenharmony_ci
27928c2ecf20Sopenharmony_ci		_R(node)
27938c2ecf20Sopenharmony_ci		_R(size)
27948c2ecf20Sopenharmony_ci
27958c2ecf20Sopenharmony_ci		#undef _R
27968c2ecf20Sopenharmony_ci
27978c2ecf20Sopenharmony_ci		if (do_read_bitmap(ff, &n.set, &n.size))
27988c2ecf20Sopenharmony_ci			goto out;
27998c2ecf20Sopenharmony_ci
28008c2ecf20Sopenharmony_ci		nodes[i] = n;
28018c2ecf20Sopenharmony_ci	}
28028c2ecf20Sopenharmony_ci
28038c2ecf20Sopenharmony_ci	ff->ph->env.memory_bsize    = bsize;
28048c2ecf20Sopenharmony_ci	ff->ph->env.memory_nodes    = nodes;
28058c2ecf20Sopenharmony_ci	ff->ph->env.nr_memory_nodes = nr;
28068c2ecf20Sopenharmony_ci	ret = 0;
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_ciout:
28098c2ecf20Sopenharmony_ci	if (ret)
28108c2ecf20Sopenharmony_ci		free(nodes);
28118c2ecf20Sopenharmony_ci	return ret;
28128c2ecf20Sopenharmony_ci}
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_cistatic int process_clockid(struct feat_fd *ff,
28158c2ecf20Sopenharmony_ci			   void *data __maybe_unused)
28168c2ecf20Sopenharmony_ci{
28178c2ecf20Sopenharmony_ci	if (do_read_u64(ff, &ff->ph->env.clock.clockid_res_ns))
28188c2ecf20Sopenharmony_ci		return -1;
28198c2ecf20Sopenharmony_ci
28208c2ecf20Sopenharmony_ci	return 0;
28218c2ecf20Sopenharmony_ci}
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_cistatic int process_clock_data(struct feat_fd *ff,
28248c2ecf20Sopenharmony_ci			      void *_data __maybe_unused)
28258c2ecf20Sopenharmony_ci{
28268c2ecf20Sopenharmony_ci	u32 data32;
28278c2ecf20Sopenharmony_ci	u64 data64;
28288c2ecf20Sopenharmony_ci
28298c2ecf20Sopenharmony_ci	/* version */
28308c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &data32))
28318c2ecf20Sopenharmony_ci		return -1;
28328c2ecf20Sopenharmony_ci
28338c2ecf20Sopenharmony_ci	if (data32 != 1)
28348c2ecf20Sopenharmony_ci		return -1;
28358c2ecf20Sopenharmony_ci
28368c2ecf20Sopenharmony_ci	/* clockid */
28378c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &data32))
28388c2ecf20Sopenharmony_ci		return -1;
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	ff->ph->env.clock.clockid = data32;
28418c2ecf20Sopenharmony_ci
28428c2ecf20Sopenharmony_ci	/* TOD ref time */
28438c2ecf20Sopenharmony_ci	if (do_read_u64(ff, &data64))
28448c2ecf20Sopenharmony_ci		return -1;
28458c2ecf20Sopenharmony_ci
28468c2ecf20Sopenharmony_ci	ff->ph->env.clock.tod_ns = data64;
28478c2ecf20Sopenharmony_ci
28488c2ecf20Sopenharmony_ci	/* clockid ref time */
28498c2ecf20Sopenharmony_ci	if (do_read_u64(ff, &data64))
28508c2ecf20Sopenharmony_ci		return -1;
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	ff->ph->env.clock.clockid_ns = data64;
28538c2ecf20Sopenharmony_ci	ff->ph->env.clock.enabled = true;
28548c2ecf20Sopenharmony_ci	return 0;
28558c2ecf20Sopenharmony_ci}
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_cistatic int process_dir_format(struct feat_fd *ff,
28588c2ecf20Sopenharmony_ci			      void *_data __maybe_unused)
28598c2ecf20Sopenharmony_ci{
28608c2ecf20Sopenharmony_ci	struct perf_session *session;
28618c2ecf20Sopenharmony_ci	struct perf_data *data;
28628c2ecf20Sopenharmony_ci
28638c2ecf20Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
28648c2ecf20Sopenharmony_ci	data = session->data;
28658c2ecf20Sopenharmony_ci
28668c2ecf20Sopenharmony_ci	if (WARN_ON(!perf_data__is_dir(data)))
28678c2ecf20Sopenharmony_ci		return -1;
28688c2ecf20Sopenharmony_ci
28698c2ecf20Sopenharmony_ci	return do_read_u64(ff, &data->dir.version);
28708c2ecf20Sopenharmony_ci}
28718c2ecf20Sopenharmony_ci
28728c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
28738c2ecf20Sopenharmony_cistatic int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused)
28748c2ecf20Sopenharmony_ci{
28758c2ecf20Sopenharmony_ci	struct bpf_prog_info_linear *info_linear;
28768c2ecf20Sopenharmony_ci	struct bpf_prog_info_node *info_node;
28778c2ecf20Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
28788c2ecf20Sopenharmony_ci	u32 count, i;
28798c2ecf20Sopenharmony_ci	int err = -1;
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	if (ff->ph->needs_swap) {
28828c2ecf20Sopenharmony_ci		pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n");
28838c2ecf20Sopenharmony_ci		return 0;
28848c2ecf20Sopenharmony_ci	}
28858c2ecf20Sopenharmony_ci
28868c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &count))
28878c2ecf20Sopenharmony_ci		return -1;
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	down_write(&env->bpf_progs.lock);
28908c2ecf20Sopenharmony_ci
28918c2ecf20Sopenharmony_ci	for (i = 0; i < count; ++i) {
28928c2ecf20Sopenharmony_ci		u32 info_len, data_len;
28938c2ecf20Sopenharmony_ci
28948c2ecf20Sopenharmony_ci		info_linear = NULL;
28958c2ecf20Sopenharmony_ci		info_node = NULL;
28968c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &info_len))
28978c2ecf20Sopenharmony_ci			goto out;
28988c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &data_len))
28998c2ecf20Sopenharmony_ci			goto out;
29008c2ecf20Sopenharmony_ci
29018c2ecf20Sopenharmony_ci		if (info_len > sizeof(struct bpf_prog_info)) {
29028c2ecf20Sopenharmony_ci			pr_warning("detected invalid bpf_prog_info\n");
29038c2ecf20Sopenharmony_ci			goto out;
29048c2ecf20Sopenharmony_ci		}
29058c2ecf20Sopenharmony_ci
29068c2ecf20Sopenharmony_ci		info_linear = malloc(sizeof(struct bpf_prog_info_linear) +
29078c2ecf20Sopenharmony_ci				     data_len);
29088c2ecf20Sopenharmony_ci		if (!info_linear)
29098c2ecf20Sopenharmony_ci			goto out;
29108c2ecf20Sopenharmony_ci		info_linear->info_len = sizeof(struct bpf_prog_info);
29118c2ecf20Sopenharmony_ci		info_linear->data_len = data_len;
29128c2ecf20Sopenharmony_ci		if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
29138c2ecf20Sopenharmony_ci			goto out;
29148c2ecf20Sopenharmony_ci		if (__do_read(ff, &info_linear->info, info_len))
29158c2ecf20Sopenharmony_ci			goto out;
29168c2ecf20Sopenharmony_ci		if (info_len < sizeof(struct bpf_prog_info))
29178c2ecf20Sopenharmony_ci			memset(((void *)(&info_linear->info)) + info_len, 0,
29188c2ecf20Sopenharmony_ci			       sizeof(struct bpf_prog_info) - info_len);
29198c2ecf20Sopenharmony_ci
29208c2ecf20Sopenharmony_ci		if (__do_read(ff, info_linear->data, data_len))
29218c2ecf20Sopenharmony_ci			goto out;
29228c2ecf20Sopenharmony_ci
29238c2ecf20Sopenharmony_ci		info_node = malloc(sizeof(struct bpf_prog_info_node));
29248c2ecf20Sopenharmony_ci		if (!info_node)
29258c2ecf20Sopenharmony_ci			goto out;
29268c2ecf20Sopenharmony_ci
29278c2ecf20Sopenharmony_ci		/* after reading from file, translate offset to address */
29288c2ecf20Sopenharmony_ci		bpf_program__bpil_offs_to_addr(info_linear);
29298c2ecf20Sopenharmony_ci		info_node->info_linear = info_linear;
29308c2ecf20Sopenharmony_ci		__perf_env__insert_bpf_prog_info(env, info_node);
29318c2ecf20Sopenharmony_ci	}
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci	up_write(&env->bpf_progs.lock);
29348c2ecf20Sopenharmony_ci	return 0;
29358c2ecf20Sopenharmony_ciout:
29368c2ecf20Sopenharmony_ci	free(info_linear);
29378c2ecf20Sopenharmony_ci	free(info_node);
29388c2ecf20Sopenharmony_ci	up_write(&env->bpf_progs.lock);
29398c2ecf20Sopenharmony_ci	return err;
29408c2ecf20Sopenharmony_ci}
29418c2ecf20Sopenharmony_ci#else // HAVE_LIBBPF_SUPPORT
29428c2ecf20Sopenharmony_cistatic int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data __maybe_unused)
29438c2ecf20Sopenharmony_ci{
29448c2ecf20Sopenharmony_ci	return 0;
29458c2ecf20Sopenharmony_ci}
29468c2ecf20Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_cistatic int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
29498c2ecf20Sopenharmony_ci{
29508c2ecf20Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
29518c2ecf20Sopenharmony_ci	struct btf_node *node = NULL;
29528c2ecf20Sopenharmony_ci	u32 count, i;
29538c2ecf20Sopenharmony_ci	int err = -1;
29548c2ecf20Sopenharmony_ci
29558c2ecf20Sopenharmony_ci	if (ff->ph->needs_swap) {
29568c2ecf20Sopenharmony_ci		pr_warning("interpreting btf from systems with endianity is not yet supported\n");
29578c2ecf20Sopenharmony_ci		return 0;
29588c2ecf20Sopenharmony_ci	}
29598c2ecf20Sopenharmony_ci
29608c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &count))
29618c2ecf20Sopenharmony_ci		return -1;
29628c2ecf20Sopenharmony_ci
29638c2ecf20Sopenharmony_ci	down_write(&env->bpf_progs.lock);
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_ci	for (i = 0; i < count; ++i) {
29668c2ecf20Sopenharmony_ci		u32 id, data_size;
29678c2ecf20Sopenharmony_ci
29688c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &id))
29698c2ecf20Sopenharmony_ci			goto out;
29708c2ecf20Sopenharmony_ci		if (do_read_u32(ff, &data_size))
29718c2ecf20Sopenharmony_ci			goto out;
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_ci		node = malloc(sizeof(struct btf_node) + data_size);
29748c2ecf20Sopenharmony_ci		if (!node)
29758c2ecf20Sopenharmony_ci			goto out;
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci		node->id = id;
29788c2ecf20Sopenharmony_ci		node->data_size = data_size;
29798c2ecf20Sopenharmony_ci
29808c2ecf20Sopenharmony_ci		if (__do_read(ff, node->data, data_size))
29818c2ecf20Sopenharmony_ci			goto out;
29828c2ecf20Sopenharmony_ci
29838c2ecf20Sopenharmony_ci		__perf_env__insert_btf(env, node);
29848c2ecf20Sopenharmony_ci		node = NULL;
29858c2ecf20Sopenharmony_ci	}
29868c2ecf20Sopenharmony_ci
29878c2ecf20Sopenharmony_ci	err = 0;
29888c2ecf20Sopenharmony_ciout:
29898c2ecf20Sopenharmony_ci	up_write(&env->bpf_progs.lock);
29908c2ecf20Sopenharmony_ci	free(node);
29918c2ecf20Sopenharmony_ci	return err;
29928c2ecf20Sopenharmony_ci}
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_cistatic int process_compressed(struct feat_fd *ff,
29958c2ecf20Sopenharmony_ci			      void *data __maybe_unused)
29968c2ecf20Sopenharmony_ci{
29978c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_ver)))
29988c2ecf20Sopenharmony_ci		return -1;
29998c2ecf20Sopenharmony_ci
30008c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_type)))
30018c2ecf20Sopenharmony_ci		return -1;
30028c2ecf20Sopenharmony_ci
30038c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_level)))
30048c2ecf20Sopenharmony_ci		return -1;
30058c2ecf20Sopenharmony_ci
30068c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_ratio)))
30078c2ecf20Sopenharmony_ci		return -1;
30088c2ecf20Sopenharmony_ci
30098c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_mmap_len)))
30108c2ecf20Sopenharmony_ci		return -1;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	return 0;
30138c2ecf20Sopenharmony_ci}
30148c2ecf20Sopenharmony_ci
30158c2ecf20Sopenharmony_cistatic int process_cpu_pmu_caps(struct feat_fd *ff,
30168c2ecf20Sopenharmony_ci				void *data __maybe_unused)
30178c2ecf20Sopenharmony_ci{
30188c2ecf20Sopenharmony_ci	char *name, *value;
30198c2ecf20Sopenharmony_ci	struct strbuf sb;
30208c2ecf20Sopenharmony_ci	u32 nr_caps;
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_ci	if (do_read_u32(ff, &nr_caps))
30238c2ecf20Sopenharmony_ci		return -1;
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_ci	if (!nr_caps) {
30268c2ecf20Sopenharmony_ci		pr_debug("cpu pmu capabilities not available\n");
30278c2ecf20Sopenharmony_ci		return 0;
30288c2ecf20Sopenharmony_ci	}
30298c2ecf20Sopenharmony_ci
30308c2ecf20Sopenharmony_ci	ff->ph->env.nr_cpu_pmu_caps = nr_caps;
30318c2ecf20Sopenharmony_ci
30328c2ecf20Sopenharmony_ci	if (strbuf_init(&sb, 128) < 0)
30338c2ecf20Sopenharmony_ci		return -1;
30348c2ecf20Sopenharmony_ci
30358c2ecf20Sopenharmony_ci	while (nr_caps--) {
30368c2ecf20Sopenharmony_ci		name = do_read_string(ff);
30378c2ecf20Sopenharmony_ci		if (!name)
30388c2ecf20Sopenharmony_ci			goto error;
30398c2ecf20Sopenharmony_ci
30408c2ecf20Sopenharmony_ci		value = do_read_string(ff);
30418c2ecf20Sopenharmony_ci		if (!value)
30428c2ecf20Sopenharmony_ci			goto free_name;
30438c2ecf20Sopenharmony_ci
30448c2ecf20Sopenharmony_ci		if (strbuf_addf(&sb, "%s=%s", name, value) < 0)
30458c2ecf20Sopenharmony_ci			goto free_value;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci		/* include a NULL character at the end */
30488c2ecf20Sopenharmony_ci		if (strbuf_add(&sb, "", 1) < 0)
30498c2ecf20Sopenharmony_ci			goto free_value;
30508c2ecf20Sopenharmony_ci
30518c2ecf20Sopenharmony_ci		if (!strcmp(name, "branches"))
30528c2ecf20Sopenharmony_ci			ff->ph->env.max_branches = atoi(value);
30538c2ecf20Sopenharmony_ci
30548c2ecf20Sopenharmony_ci		free(value);
30558c2ecf20Sopenharmony_ci		free(name);
30568c2ecf20Sopenharmony_ci	}
30578c2ecf20Sopenharmony_ci	ff->ph->env.cpu_pmu_caps = strbuf_detach(&sb, NULL);
30588c2ecf20Sopenharmony_ci	return 0;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_cifree_value:
30618c2ecf20Sopenharmony_ci	free(value);
30628c2ecf20Sopenharmony_cifree_name:
30638c2ecf20Sopenharmony_ci	free(name);
30648c2ecf20Sopenharmony_cierror:
30658c2ecf20Sopenharmony_ci	strbuf_release(&sb);
30668c2ecf20Sopenharmony_ci	return -1;
30678c2ecf20Sopenharmony_ci}
30688c2ecf20Sopenharmony_ci
30698c2ecf20Sopenharmony_ci#define FEAT_OPR(n, func, __full_only) \
30708c2ecf20Sopenharmony_ci	[HEADER_##n] = {					\
30718c2ecf20Sopenharmony_ci		.name	    = __stringify(n),			\
30728c2ecf20Sopenharmony_ci		.write	    = write_##func,			\
30738c2ecf20Sopenharmony_ci		.print	    = print_##func,			\
30748c2ecf20Sopenharmony_ci		.full_only  = __full_only,			\
30758c2ecf20Sopenharmony_ci		.process    = process_##func,			\
30768c2ecf20Sopenharmony_ci		.synthesize = true				\
30778c2ecf20Sopenharmony_ci	}
30788c2ecf20Sopenharmony_ci
30798c2ecf20Sopenharmony_ci#define FEAT_OPN(n, func, __full_only) \
30808c2ecf20Sopenharmony_ci	[HEADER_##n] = {					\
30818c2ecf20Sopenharmony_ci		.name	    = __stringify(n),			\
30828c2ecf20Sopenharmony_ci		.write	    = write_##func,			\
30838c2ecf20Sopenharmony_ci		.print	    = print_##func,			\
30848c2ecf20Sopenharmony_ci		.full_only  = __full_only,			\
30858c2ecf20Sopenharmony_ci		.process    = process_##func			\
30868c2ecf20Sopenharmony_ci	}
30878c2ecf20Sopenharmony_ci
30888c2ecf20Sopenharmony_ci/* feature_ops not implemented: */
30898c2ecf20Sopenharmony_ci#define print_tracing_data	NULL
30908c2ecf20Sopenharmony_ci#define print_build_id		NULL
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci#define process_branch_stack	NULL
30938c2ecf20Sopenharmony_ci#define process_stat		NULL
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci// Only used in util/synthetic-events.c
30968c2ecf20Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE];
30978c2ecf20Sopenharmony_ci
30988c2ecf20Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
30998c2ecf20Sopenharmony_ci	FEAT_OPN(TRACING_DATA,	tracing_data,	false),
31008c2ecf20Sopenharmony_ci	FEAT_OPN(BUILD_ID,	build_id,	false),
31018c2ecf20Sopenharmony_ci	FEAT_OPR(HOSTNAME,	hostname,	false),
31028c2ecf20Sopenharmony_ci	FEAT_OPR(OSRELEASE,	osrelease,	false),
31038c2ecf20Sopenharmony_ci	FEAT_OPR(VERSION,	version,	false),
31048c2ecf20Sopenharmony_ci	FEAT_OPR(ARCH,		arch,		false),
31058c2ecf20Sopenharmony_ci	FEAT_OPR(NRCPUS,	nrcpus,		false),
31068c2ecf20Sopenharmony_ci	FEAT_OPR(CPUDESC,	cpudesc,	false),
31078c2ecf20Sopenharmony_ci	FEAT_OPR(CPUID,		cpuid,		false),
31088c2ecf20Sopenharmony_ci	FEAT_OPR(TOTAL_MEM,	total_mem,	false),
31098c2ecf20Sopenharmony_ci	FEAT_OPR(EVENT_DESC,	event_desc,	false),
31108c2ecf20Sopenharmony_ci	FEAT_OPR(CMDLINE,	cmdline,	false),
31118c2ecf20Sopenharmony_ci	FEAT_OPR(CPU_TOPOLOGY,	cpu_topology,	true),
31128c2ecf20Sopenharmony_ci	FEAT_OPR(NUMA_TOPOLOGY,	numa_topology,	true),
31138c2ecf20Sopenharmony_ci	FEAT_OPN(BRANCH_STACK,	branch_stack,	false),
31148c2ecf20Sopenharmony_ci	FEAT_OPR(PMU_MAPPINGS,	pmu_mappings,	false),
31158c2ecf20Sopenharmony_ci	FEAT_OPR(GROUP_DESC,	group_desc,	false),
31168c2ecf20Sopenharmony_ci	FEAT_OPN(AUXTRACE,	auxtrace,	false),
31178c2ecf20Sopenharmony_ci	FEAT_OPN(STAT,		stat,		false),
31188c2ecf20Sopenharmony_ci	FEAT_OPN(CACHE,		cache,		true),
31198c2ecf20Sopenharmony_ci	FEAT_OPR(SAMPLE_TIME,	sample_time,	false),
31208c2ecf20Sopenharmony_ci	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
31218c2ecf20Sopenharmony_ci	FEAT_OPR(CLOCKID,	clockid,	false),
31228c2ecf20Sopenharmony_ci	FEAT_OPN(DIR_FORMAT,	dir_format,	false),
31238c2ecf20Sopenharmony_ci	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false),
31248c2ecf20Sopenharmony_ci	FEAT_OPR(BPF_BTF,       bpf_btf,        false),
31258c2ecf20Sopenharmony_ci	FEAT_OPR(COMPRESSED,	compressed,	false),
31268c2ecf20Sopenharmony_ci	FEAT_OPR(CPU_PMU_CAPS,	cpu_pmu_caps,	false),
31278c2ecf20Sopenharmony_ci	FEAT_OPR(CLOCK_DATA,	clock_data,	false),
31288c2ecf20Sopenharmony_ci};
31298c2ecf20Sopenharmony_ci
31308c2ecf20Sopenharmony_cistruct header_print_data {
31318c2ecf20Sopenharmony_ci	FILE *fp;
31328c2ecf20Sopenharmony_ci	bool full; /* extended list of headers */
31338c2ecf20Sopenharmony_ci};
31348c2ecf20Sopenharmony_ci
31358c2ecf20Sopenharmony_cistatic int perf_file_section__fprintf_info(struct perf_file_section *section,
31368c2ecf20Sopenharmony_ci					   struct perf_header *ph,
31378c2ecf20Sopenharmony_ci					   int feat, int fd, void *data)
31388c2ecf20Sopenharmony_ci{
31398c2ecf20Sopenharmony_ci	struct header_print_data *hd = data;
31408c2ecf20Sopenharmony_ci	struct feat_fd ff;
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
31438c2ecf20Sopenharmony_ci		pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
31448c2ecf20Sopenharmony_ci				"%d, continuing...\n", section->offset, feat);
31458c2ecf20Sopenharmony_ci		return 0;
31468c2ecf20Sopenharmony_ci	}
31478c2ecf20Sopenharmony_ci	if (feat >= HEADER_LAST_FEATURE) {
31488c2ecf20Sopenharmony_ci		pr_warning("unknown feature %d\n", feat);
31498c2ecf20Sopenharmony_ci		return 0;
31508c2ecf20Sopenharmony_ci	}
31518c2ecf20Sopenharmony_ci	if (!feat_ops[feat].print)
31528c2ecf20Sopenharmony_ci		return 0;
31538c2ecf20Sopenharmony_ci
31548c2ecf20Sopenharmony_ci	ff = (struct  feat_fd) {
31558c2ecf20Sopenharmony_ci		.fd = fd,
31568c2ecf20Sopenharmony_ci		.ph = ph,
31578c2ecf20Sopenharmony_ci	};
31588c2ecf20Sopenharmony_ci
31598c2ecf20Sopenharmony_ci	if (!feat_ops[feat].full_only || hd->full)
31608c2ecf20Sopenharmony_ci		feat_ops[feat].print(&ff, hd->fp);
31618c2ecf20Sopenharmony_ci	else
31628c2ecf20Sopenharmony_ci		fprintf(hd->fp, "# %s info available, use -I to display\n",
31638c2ecf20Sopenharmony_ci			feat_ops[feat].name);
31648c2ecf20Sopenharmony_ci
31658c2ecf20Sopenharmony_ci	return 0;
31668c2ecf20Sopenharmony_ci}
31678c2ecf20Sopenharmony_ci
31688c2ecf20Sopenharmony_ciint perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
31698c2ecf20Sopenharmony_ci{
31708c2ecf20Sopenharmony_ci	struct header_print_data hd;
31718c2ecf20Sopenharmony_ci	struct perf_header *header = &session->header;
31728c2ecf20Sopenharmony_ci	int fd = perf_data__fd(session->data);
31738c2ecf20Sopenharmony_ci	struct stat st;
31748c2ecf20Sopenharmony_ci	time_t stctime;
31758c2ecf20Sopenharmony_ci	int ret, bit;
31768c2ecf20Sopenharmony_ci
31778c2ecf20Sopenharmony_ci	hd.fp = fp;
31788c2ecf20Sopenharmony_ci	hd.full = full;
31798c2ecf20Sopenharmony_ci
31808c2ecf20Sopenharmony_ci	ret = fstat(fd, &st);
31818c2ecf20Sopenharmony_ci	if (ret == -1)
31828c2ecf20Sopenharmony_ci		return -1;
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci	stctime = st.st_mtime;
31858c2ecf20Sopenharmony_ci	fprintf(fp, "# captured on    : %s", ctime(&stctime));
31868c2ecf20Sopenharmony_ci
31878c2ecf20Sopenharmony_ci	fprintf(fp, "# header version : %u\n", header->version);
31888c2ecf20Sopenharmony_ci	fprintf(fp, "# data offset    : %" PRIu64 "\n", header->data_offset);
31898c2ecf20Sopenharmony_ci	fprintf(fp, "# data size      : %" PRIu64 "\n", header->data_size);
31908c2ecf20Sopenharmony_ci	fprintf(fp, "# feat offset    : %" PRIu64 "\n", header->feat_offset);
31918c2ecf20Sopenharmony_ci
31928c2ecf20Sopenharmony_ci	perf_header__process_sections(header, fd, &hd,
31938c2ecf20Sopenharmony_ci				      perf_file_section__fprintf_info);
31948c2ecf20Sopenharmony_ci
31958c2ecf20Sopenharmony_ci	if (session->data->is_pipe)
31968c2ecf20Sopenharmony_ci		return 0;
31978c2ecf20Sopenharmony_ci
31988c2ecf20Sopenharmony_ci	fprintf(fp, "# missing features: ");
31998c2ecf20Sopenharmony_ci	for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
32008c2ecf20Sopenharmony_ci		if (bit)
32018c2ecf20Sopenharmony_ci			fprintf(fp, "%s ", feat_ops[bit].name);
32028c2ecf20Sopenharmony_ci	}
32038c2ecf20Sopenharmony_ci
32048c2ecf20Sopenharmony_ci	fprintf(fp, "\n");
32058c2ecf20Sopenharmony_ci	return 0;
32068c2ecf20Sopenharmony_ci}
32078c2ecf20Sopenharmony_ci
32088c2ecf20Sopenharmony_cistatic int do_write_feat(struct feat_fd *ff, int type,
32098c2ecf20Sopenharmony_ci			 struct perf_file_section **p,
32108c2ecf20Sopenharmony_ci			 struct evlist *evlist)
32118c2ecf20Sopenharmony_ci{
32128c2ecf20Sopenharmony_ci	int err;
32138c2ecf20Sopenharmony_ci	int ret = 0;
32148c2ecf20Sopenharmony_ci
32158c2ecf20Sopenharmony_ci	if (perf_header__has_feat(ff->ph, type)) {
32168c2ecf20Sopenharmony_ci		if (!feat_ops[type].write)
32178c2ecf20Sopenharmony_ci			return -1;
32188c2ecf20Sopenharmony_ci
32198c2ecf20Sopenharmony_ci		if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
32208c2ecf20Sopenharmony_ci			return -1;
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_ci		(*p)->offset = lseek(ff->fd, 0, SEEK_CUR);
32238c2ecf20Sopenharmony_ci
32248c2ecf20Sopenharmony_ci		err = feat_ops[type].write(ff, evlist);
32258c2ecf20Sopenharmony_ci		if (err < 0) {
32268c2ecf20Sopenharmony_ci			pr_debug("failed to write feature %s\n", feat_ops[type].name);
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_ci			/* undo anything written */
32298c2ecf20Sopenharmony_ci			lseek(ff->fd, (*p)->offset, SEEK_SET);
32308c2ecf20Sopenharmony_ci
32318c2ecf20Sopenharmony_ci			return -1;
32328c2ecf20Sopenharmony_ci		}
32338c2ecf20Sopenharmony_ci		(*p)->size = lseek(ff->fd, 0, SEEK_CUR) - (*p)->offset;
32348c2ecf20Sopenharmony_ci		(*p)++;
32358c2ecf20Sopenharmony_ci	}
32368c2ecf20Sopenharmony_ci	return ret;
32378c2ecf20Sopenharmony_ci}
32388c2ecf20Sopenharmony_ci
32398c2ecf20Sopenharmony_cistatic int perf_header__adds_write(struct perf_header *header,
32408c2ecf20Sopenharmony_ci				   struct evlist *evlist, int fd)
32418c2ecf20Sopenharmony_ci{
32428c2ecf20Sopenharmony_ci	int nr_sections;
32438c2ecf20Sopenharmony_ci	struct feat_fd ff;
32448c2ecf20Sopenharmony_ci	struct perf_file_section *feat_sec, *p;
32458c2ecf20Sopenharmony_ci	int sec_size;
32468c2ecf20Sopenharmony_ci	u64 sec_start;
32478c2ecf20Sopenharmony_ci	int feat;
32488c2ecf20Sopenharmony_ci	int err;
32498c2ecf20Sopenharmony_ci
32508c2ecf20Sopenharmony_ci	ff = (struct feat_fd){
32518c2ecf20Sopenharmony_ci		.fd  = fd,
32528c2ecf20Sopenharmony_ci		.ph = header,
32538c2ecf20Sopenharmony_ci	};
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_ci	nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
32568c2ecf20Sopenharmony_ci	if (!nr_sections)
32578c2ecf20Sopenharmony_ci		return 0;
32588c2ecf20Sopenharmony_ci
32598c2ecf20Sopenharmony_ci	feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
32608c2ecf20Sopenharmony_ci	if (feat_sec == NULL)
32618c2ecf20Sopenharmony_ci		return -ENOMEM;
32628c2ecf20Sopenharmony_ci
32638c2ecf20Sopenharmony_ci	sec_size = sizeof(*feat_sec) * nr_sections;
32648c2ecf20Sopenharmony_ci
32658c2ecf20Sopenharmony_ci	sec_start = header->feat_offset;
32668c2ecf20Sopenharmony_ci	lseek(fd, sec_start + sec_size, SEEK_SET);
32678c2ecf20Sopenharmony_ci
32688c2ecf20Sopenharmony_ci	for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
32698c2ecf20Sopenharmony_ci		if (do_write_feat(&ff, feat, &p, evlist))
32708c2ecf20Sopenharmony_ci			perf_header__clear_feat(header, feat);
32718c2ecf20Sopenharmony_ci	}
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	lseek(fd, sec_start, SEEK_SET);
32748c2ecf20Sopenharmony_ci	/*
32758c2ecf20Sopenharmony_ci	 * may write more than needed due to dropped feature, but
32768c2ecf20Sopenharmony_ci	 * this is okay, reader will skip the missing entries
32778c2ecf20Sopenharmony_ci	 */
32788c2ecf20Sopenharmony_ci	err = do_write(&ff, feat_sec, sec_size);
32798c2ecf20Sopenharmony_ci	if (err < 0)
32808c2ecf20Sopenharmony_ci		pr_debug("failed to write feature section\n");
32818c2ecf20Sopenharmony_ci	free(feat_sec);
32828c2ecf20Sopenharmony_ci	return err;
32838c2ecf20Sopenharmony_ci}
32848c2ecf20Sopenharmony_ci
32858c2ecf20Sopenharmony_ciint perf_header__write_pipe(int fd)
32868c2ecf20Sopenharmony_ci{
32878c2ecf20Sopenharmony_ci	struct perf_pipe_file_header f_header;
32888c2ecf20Sopenharmony_ci	struct feat_fd ff;
32898c2ecf20Sopenharmony_ci	int err;
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ci	ff = (struct feat_fd){ .fd = fd };
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_ci	f_header = (struct perf_pipe_file_header){
32948c2ecf20Sopenharmony_ci		.magic	   = PERF_MAGIC,
32958c2ecf20Sopenharmony_ci		.size	   = sizeof(f_header),
32968c2ecf20Sopenharmony_ci	};
32978c2ecf20Sopenharmony_ci
32988c2ecf20Sopenharmony_ci	err = do_write(&ff, &f_header, sizeof(f_header));
32998c2ecf20Sopenharmony_ci	if (err < 0) {
33008c2ecf20Sopenharmony_ci		pr_debug("failed to write perf pipe header\n");
33018c2ecf20Sopenharmony_ci		return err;
33028c2ecf20Sopenharmony_ci	}
33038c2ecf20Sopenharmony_ci
33048c2ecf20Sopenharmony_ci	return 0;
33058c2ecf20Sopenharmony_ci}
33068c2ecf20Sopenharmony_ci
33078c2ecf20Sopenharmony_ciint perf_session__write_header(struct perf_session *session,
33088c2ecf20Sopenharmony_ci			       struct evlist *evlist,
33098c2ecf20Sopenharmony_ci			       int fd, bool at_exit)
33108c2ecf20Sopenharmony_ci{
33118c2ecf20Sopenharmony_ci	struct perf_file_header f_header;
33128c2ecf20Sopenharmony_ci	struct perf_file_attr   f_attr;
33138c2ecf20Sopenharmony_ci	struct perf_header *header = &session->header;
33148c2ecf20Sopenharmony_ci	struct evsel *evsel;
33158c2ecf20Sopenharmony_ci	struct feat_fd ff;
33168c2ecf20Sopenharmony_ci	u64 attr_offset;
33178c2ecf20Sopenharmony_ci	int err;
33188c2ecf20Sopenharmony_ci
33198c2ecf20Sopenharmony_ci	ff = (struct feat_fd){ .fd = fd};
33208c2ecf20Sopenharmony_ci	lseek(fd, sizeof(f_header), SEEK_SET);
33218c2ecf20Sopenharmony_ci
33228c2ecf20Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
33238c2ecf20Sopenharmony_ci		evsel->id_offset = lseek(fd, 0, SEEK_CUR);
33248c2ecf20Sopenharmony_ci		err = do_write(&ff, evsel->core.id, evsel->core.ids * sizeof(u64));
33258c2ecf20Sopenharmony_ci		if (err < 0) {
33268c2ecf20Sopenharmony_ci			pr_debug("failed to write perf header\n");
33278c2ecf20Sopenharmony_ci			return err;
33288c2ecf20Sopenharmony_ci		}
33298c2ecf20Sopenharmony_ci	}
33308c2ecf20Sopenharmony_ci
33318c2ecf20Sopenharmony_ci	attr_offset = lseek(ff.fd, 0, SEEK_CUR);
33328c2ecf20Sopenharmony_ci
33338c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
33348c2ecf20Sopenharmony_ci		f_attr = (struct perf_file_attr){
33358c2ecf20Sopenharmony_ci			.attr = evsel->core.attr,
33368c2ecf20Sopenharmony_ci			.ids  = {
33378c2ecf20Sopenharmony_ci				.offset = evsel->id_offset,
33388c2ecf20Sopenharmony_ci				.size   = evsel->core.ids * sizeof(u64),
33398c2ecf20Sopenharmony_ci			}
33408c2ecf20Sopenharmony_ci		};
33418c2ecf20Sopenharmony_ci		err = do_write(&ff, &f_attr, sizeof(f_attr));
33428c2ecf20Sopenharmony_ci		if (err < 0) {
33438c2ecf20Sopenharmony_ci			pr_debug("failed to write perf header attribute\n");
33448c2ecf20Sopenharmony_ci			return err;
33458c2ecf20Sopenharmony_ci		}
33468c2ecf20Sopenharmony_ci	}
33478c2ecf20Sopenharmony_ci
33488c2ecf20Sopenharmony_ci	if (!header->data_offset)
33498c2ecf20Sopenharmony_ci		header->data_offset = lseek(fd, 0, SEEK_CUR);
33508c2ecf20Sopenharmony_ci	header->feat_offset = header->data_offset + header->data_size;
33518c2ecf20Sopenharmony_ci
33528c2ecf20Sopenharmony_ci	if (at_exit) {
33538c2ecf20Sopenharmony_ci		err = perf_header__adds_write(header, evlist, fd);
33548c2ecf20Sopenharmony_ci		if (err < 0)
33558c2ecf20Sopenharmony_ci			return err;
33568c2ecf20Sopenharmony_ci	}
33578c2ecf20Sopenharmony_ci
33588c2ecf20Sopenharmony_ci	f_header = (struct perf_file_header){
33598c2ecf20Sopenharmony_ci		.magic	   = PERF_MAGIC,
33608c2ecf20Sopenharmony_ci		.size	   = sizeof(f_header),
33618c2ecf20Sopenharmony_ci		.attr_size = sizeof(f_attr),
33628c2ecf20Sopenharmony_ci		.attrs = {
33638c2ecf20Sopenharmony_ci			.offset = attr_offset,
33648c2ecf20Sopenharmony_ci			.size   = evlist->core.nr_entries * sizeof(f_attr),
33658c2ecf20Sopenharmony_ci		},
33668c2ecf20Sopenharmony_ci		.data = {
33678c2ecf20Sopenharmony_ci			.offset = header->data_offset,
33688c2ecf20Sopenharmony_ci			.size	= header->data_size,
33698c2ecf20Sopenharmony_ci		},
33708c2ecf20Sopenharmony_ci		/* event_types is ignored, store zeros */
33718c2ecf20Sopenharmony_ci	};
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci	memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
33748c2ecf20Sopenharmony_ci
33758c2ecf20Sopenharmony_ci	lseek(fd, 0, SEEK_SET);
33768c2ecf20Sopenharmony_ci	err = do_write(&ff, &f_header, sizeof(f_header));
33778c2ecf20Sopenharmony_ci	if (err < 0) {
33788c2ecf20Sopenharmony_ci		pr_debug("failed to write perf header\n");
33798c2ecf20Sopenharmony_ci		return err;
33808c2ecf20Sopenharmony_ci	}
33818c2ecf20Sopenharmony_ci	lseek(fd, header->data_offset + header->data_size, SEEK_SET);
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ci	return 0;
33848c2ecf20Sopenharmony_ci}
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_cistatic int perf_header__getbuffer64(struct perf_header *header,
33878c2ecf20Sopenharmony_ci				    int fd, void *buf, size_t size)
33888c2ecf20Sopenharmony_ci{
33898c2ecf20Sopenharmony_ci	if (readn(fd, buf, size) <= 0)
33908c2ecf20Sopenharmony_ci		return -1;
33918c2ecf20Sopenharmony_ci
33928c2ecf20Sopenharmony_ci	if (header->needs_swap)
33938c2ecf20Sopenharmony_ci		mem_bswap_64(buf, size);
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_ci	return 0;
33968c2ecf20Sopenharmony_ci}
33978c2ecf20Sopenharmony_ci
33988c2ecf20Sopenharmony_ciint perf_header__process_sections(struct perf_header *header, int fd,
33998c2ecf20Sopenharmony_ci				  void *data,
34008c2ecf20Sopenharmony_ci				  int (*process)(struct perf_file_section *section,
34018c2ecf20Sopenharmony_ci						 struct perf_header *ph,
34028c2ecf20Sopenharmony_ci						 int feat, int fd, void *data))
34038c2ecf20Sopenharmony_ci{
34048c2ecf20Sopenharmony_ci	struct perf_file_section *feat_sec, *sec;
34058c2ecf20Sopenharmony_ci	int nr_sections;
34068c2ecf20Sopenharmony_ci	int sec_size;
34078c2ecf20Sopenharmony_ci	int feat;
34088c2ecf20Sopenharmony_ci	int err;
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci	nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
34118c2ecf20Sopenharmony_ci	if (!nr_sections)
34128c2ecf20Sopenharmony_ci		return 0;
34138c2ecf20Sopenharmony_ci
34148c2ecf20Sopenharmony_ci	feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
34158c2ecf20Sopenharmony_ci	if (!feat_sec)
34168c2ecf20Sopenharmony_ci		return -1;
34178c2ecf20Sopenharmony_ci
34188c2ecf20Sopenharmony_ci	sec_size = sizeof(*feat_sec) * nr_sections;
34198c2ecf20Sopenharmony_ci
34208c2ecf20Sopenharmony_ci	lseek(fd, header->feat_offset, SEEK_SET);
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
34238c2ecf20Sopenharmony_ci	if (err < 0)
34248c2ecf20Sopenharmony_ci		goto out_free;
34258c2ecf20Sopenharmony_ci
34268c2ecf20Sopenharmony_ci	for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) {
34278c2ecf20Sopenharmony_ci		err = process(sec++, header, feat, fd, data);
34288c2ecf20Sopenharmony_ci		if (err < 0)
34298c2ecf20Sopenharmony_ci			goto out_free;
34308c2ecf20Sopenharmony_ci	}
34318c2ecf20Sopenharmony_ci	err = 0;
34328c2ecf20Sopenharmony_ciout_free:
34338c2ecf20Sopenharmony_ci	free(feat_sec);
34348c2ecf20Sopenharmony_ci	return err;
34358c2ecf20Sopenharmony_ci}
34368c2ecf20Sopenharmony_ci
34378c2ecf20Sopenharmony_cistatic const int attr_file_abi_sizes[] = {
34388c2ecf20Sopenharmony_ci	[0] = PERF_ATTR_SIZE_VER0,
34398c2ecf20Sopenharmony_ci	[1] = PERF_ATTR_SIZE_VER1,
34408c2ecf20Sopenharmony_ci	[2] = PERF_ATTR_SIZE_VER2,
34418c2ecf20Sopenharmony_ci	[3] = PERF_ATTR_SIZE_VER3,
34428c2ecf20Sopenharmony_ci	[4] = PERF_ATTR_SIZE_VER4,
34438c2ecf20Sopenharmony_ci	0,
34448c2ecf20Sopenharmony_ci};
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci/*
34478c2ecf20Sopenharmony_ci * In the legacy file format, the magic number is not used to encode endianness.
34488c2ecf20Sopenharmony_ci * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
34498c2ecf20Sopenharmony_ci * on ABI revisions, we need to try all combinations for all endianness to
34508c2ecf20Sopenharmony_ci * detect the endianness.
34518c2ecf20Sopenharmony_ci */
34528c2ecf20Sopenharmony_cistatic int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
34538c2ecf20Sopenharmony_ci{
34548c2ecf20Sopenharmony_ci	uint64_t ref_size, attr_size;
34558c2ecf20Sopenharmony_ci	int i;
34568c2ecf20Sopenharmony_ci
34578c2ecf20Sopenharmony_ci	for (i = 0 ; attr_file_abi_sizes[i]; i++) {
34588c2ecf20Sopenharmony_ci		ref_size = attr_file_abi_sizes[i]
34598c2ecf20Sopenharmony_ci			 + sizeof(struct perf_file_section);
34608c2ecf20Sopenharmony_ci		if (hdr_sz != ref_size) {
34618c2ecf20Sopenharmony_ci			attr_size = bswap_64(hdr_sz);
34628c2ecf20Sopenharmony_ci			if (attr_size != ref_size)
34638c2ecf20Sopenharmony_ci				continue;
34648c2ecf20Sopenharmony_ci
34658c2ecf20Sopenharmony_ci			ph->needs_swap = true;
34668c2ecf20Sopenharmony_ci		}
34678c2ecf20Sopenharmony_ci		pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
34688c2ecf20Sopenharmony_ci			 i,
34698c2ecf20Sopenharmony_ci			 ph->needs_swap);
34708c2ecf20Sopenharmony_ci		return 0;
34718c2ecf20Sopenharmony_ci	}
34728c2ecf20Sopenharmony_ci	/* could not determine endianness */
34738c2ecf20Sopenharmony_ci	return -1;
34748c2ecf20Sopenharmony_ci}
34758c2ecf20Sopenharmony_ci
34768c2ecf20Sopenharmony_ci#define PERF_PIPE_HDR_VER0	16
34778c2ecf20Sopenharmony_ci
34788c2ecf20Sopenharmony_cistatic const size_t attr_pipe_abi_sizes[] = {
34798c2ecf20Sopenharmony_ci	[0] = PERF_PIPE_HDR_VER0,
34808c2ecf20Sopenharmony_ci	0,
34818c2ecf20Sopenharmony_ci};
34828c2ecf20Sopenharmony_ci
34838c2ecf20Sopenharmony_ci/*
34848c2ecf20Sopenharmony_ci * In the legacy pipe format, there is an implicit assumption that endiannesss
34858c2ecf20Sopenharmony_ci * between host recording the samples, and host parsing the samples is the
34868c2ecf20Sopenharmony_ci * same. This is not always the case given that the pipe output may always be
34878c2ecf20Sopenharmony_ci * redirected into a file and analyzed on a different machine with possibly a
34888c2ecf20Sopenharmony_ci * different endianness and perf_event ABI revsions in the perf tool itself.
34898c2ecf20Sopenharmony_ci */
34908c2ecf20Sopenharmony_cistatic int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
34918c2ecf20Sopenharmony_ci{
34928c2ecf20Sopenharmony_ci	u64 attr_size;
34938c2ecf20Sopenharmony_ci	int i;
34948c2ecf20Sopenharmony_ci
34958c2ecf20Sopenharmony_ci	for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
34968c2ecf20Sopenharmony_ci		if (hdr_sz != attr_pipe_abi_sizes[i]) {
34978c2ecf20Sopenharmony_ci			attr_size = bswap_64(hdr_sz);
34988c2ecf20Sopenharmony_ci			if (attr_size != hdr_sz)
34998c2ecf20Sopenharmony_ci				continue;
35008c2ecf20Sopenharmony_ci
35018c2ecf20Sopenharmony_ci			ph->needs_swap = true;
35028c2ecf20Sopenharmony_ci		}
35038c2ecf20Sopenharmony_ci		pr_debug("Pipe ABI%d perf.data file detected\n", i);
35048c2ecf20Sopenharmony_ci		return 0;
35058c2ecf20Sopenharmony_ci	}
35068c2ecf20Sopenharmony_ci	return -1;
35078c2ecf20Sopenharmony_ci}
35088c2ecf20Sopenharmony_ci
35098c2ecf20Sopenharmony_cibool is_perf_magic(u64 magic)
35108c2ecf20Sopenharmony_ci{
35118c2ecf20Sopenharmony_ci	if (!memcmp(&magic, __perf_magic1, sizeof(magic))
35128c2ecf20Sopenharmony_ci		|| magic == __perf_magic2
35138c2ecf20Sopenharmony_ci		|| magic == __perf_magic2_sw)
35148c2ecf20Sopenharmony_ci		return true;
35158c2ecf20Sopenharmony_ci
35168c2ecf20Sopenharmony_ci	return false;
35178c2ecf20Sopenharmony_ci}
35188c2ecf20Sopenharmony_ci
35198c2ecf20Sopenharmony_cistatic int check_magic_endian(u64 magic, uint64_t hdr_sz,
35208c2ecf20Sopenharmony_ci			      bool is_pipe, struct perf_header *ph)
35218c2ecf20Sopenharmony_ci{
35228c2ecf20Sopenharmony_ci	int ret;
35238c2ecf20Sopenharmony_ci
35248c2ecf20Sopenharmony_ci	/* check for legacy format */
35258c2ecf20Sopenharmony_ci	ret = memcmp(&magic, __perf_magic1, sizeof(magic));
35268c2ecf20Sopenharmony_ci	if (ret == 0) {
35278c2ecf20Sopenharmony_ci		ph->version = PERF_HEADER_VERSION_1;
35288c2ecf20Sopenharmony_ci		pr_debug("legacy perf.data format\n");
35298c2ecf20Sopenharmony_ci		if (is_pipe)
35308c2ecf20Sopenharmony_ci			return try_all_pipe_abis(hdr_sz, ph);
35318c2ecf20Sopenharmony_ci
35328c2ecf20Sopenharmony_ci		return try_all_file_abis(hdr_sz, ph);
35338c2ecf20Sopenharmony_ci	}
35348c2ecf20Sopenharmony_ci	/*
35358c2ecf20Sopenharmony_ci	 * the new magic number serves two purposes:
35368c2ecf20Sopenharmony_ci	 * - unique number to identify actual perf.data files
35378c2ecf20Sopenharmony_ci	 * - encode endianness of file
35388c2ecf20Sopenharmony_ci	 */
35398c2ecf20Sopenharmony_ci	ph->version = PERF_HEADER_VERSION_2;
35408c2ecf20Sopenharmony_ci
35418c2ecf20Sopenharmony_ci	/* check magic number with one endianness */
35428c2ecf20Sopenharmony_ci	if (magic == __perf_magic2)
35438c2ecf20Sopenharmony_ci		return 0;
35448c2ecf20Sopenharmony_ci
35458c2ecf20Sopenharmony_ci	/* check magic number with opposite endianness */
35468c2ecf20Sopenharmony_ci	if (magic != __perf_magic2_sw)
35478c2ecf20Sopenharmony_ci		return -1;
35488c2ecf20Sopenharmony_ci
35498c2ecf20Sopenharmony_ci	ph->needs_swap = true;
35508c2ecf20Sopenharmony_ci
35518c2ecf20Sopenharmony_ci	return 0;
35528c2ecf20Sopenharmony_ci}
35538c2ecf20Sopenharmony_ci
35548c2ecf20Sopenharmony_ciint perf_file_header__read(struct perf_file_header *header,
35558c2ecf20Sopenharmony_ci			   struct perf_header *ph, int fd)
35568c2ecf20Sopenharmony_ci{
35578c2ecf20Sopenharmony_ci	ssize_t ret;
35588c2ecf20Sopenharmony_ci
35598c2ecf20Sopenharmony_ci	lseek(fd, 0, SEEK_SET);
35608c2ecf20Sopenharmony_ci
35618c2ecf20Sopenharmony_ci	ret = readn(fd, header, sizeof(*header));
35628c2ecf20Sopenharmony_ci	if (ret <= 0)
35638c2ecf20Sopenharmony_ci		return -1;
35648c2ecf20Sopenharmony_ci
35658c2ecf20Sopenharmony_ci	if (check_magic_endian(header->magic,
35668c2ecf20Sopenharmony_ci			       header->attr_size, false, ph) < 0) {
35678c2ecf20Sopenharmony_ci		pr_debug("magic/endian check failed\n");
35688c2ecf20Sopenharmony_ci		return -1;
35698c2ecf20Sopenharmony_ci	}
35708c2ecf20Sopenharmony_ci
35718c2ecf20Sopenharmony_ci	if (ph->needs_swap) {
35728c2ecf20Sopenharmony_ci		mem_bswap_64(header, offsetof(struct perf_file_header,
35738c2ecf20Sopenharmony_ci			     adds_features));
35748c2ecf20Sopenharmony_ci	}
35758c2ecf20Sopenharmony_ci
35768c2ecf20Sopenharmony_ci	if (header->size != sizeof(*header)) {
35778c2ecf20Sopenharmony_ci		/* Support the previous format */
35788c2ecf20Sopenharmony_ci		if (header->size == offsetof(typeof(*header), adds_features))
35798c2ecf20Sopenharmony_ci			bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
35808c2ecf20Sopenharmony_ci		else
35818c2ecf20Sopenharmony_ci			return -1;
35828c2ecf20Sopenharmony_ci	} else if (ph->needs_swap) {
35838c2ecf20Sopenharmony_ci		/*
35848c2ecf20Sopenharmony_ci		 * feature bitmap is declared as an array of unsigned longs --
35858c2ecf20Sopenharmony_ci		 * not good since its size can differ between the host that
35868c2ecf20Sopenharmony_ci		 * generated the data file and the host analyzing the file.
35878c2ecf20Sopenharmony_ci		 *
35888c2ecf20Sopenharmony_ci		 * We need to handle endianness, but we don't know the size of
35898c2ecf20Sopenharmony_ci		 * the unsigned long where the file was generated. Take a best
35908c2ecf20Sopenharmony_ci		 * guess at determining it: try 64-bit swap first (ie., file
35918c2ecf20Sopenharmony_ci		 * created on a 64-bit host), and check if the hostname feature
35928c2ecf20Sopenharmony_ci		 * bit is set (this feature bit is forced on as of fbe96f2).
35938c2ecf20Sopenharmony_ci		 * If the bit is not, undo the 64-bit swap and try a 32-bit
35948c2ecf20Sopenharmony_ci		 * swap. If the hostname bit is still not set (e.g., older data
35958c2ecf20Sopenharmony_ci		 * file), punt and fallback to the original behavior --
35968c2ecf20Sopenharmony_ci		 * clearing all feature bits and setting buildid.
35978c2ecf20Sopenharmony_ci		 */
35988c2ecf20Sopenharmony_ci		mem_bswap_64(&header->adds_features,
35998c2ecf20Sopenharmony_ci			    BITS_TO_U64(HEADER_FEAT_BITS));
36008c2ecf20Sopenharmony_ci
36018c2ecf20Sopenharmony_ci		if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
36028c2ecf20Sopenharmony_ci			/* unswap as u64 */
36038c2ecf20Sopenharmony_ci			mem_bswap_64(&header->adds_features,
36048c2ecf20Sopenharmony_ci				    BITS_TO_U64(HEADER_FEAT_BITS));
36058c2ecf20Sopenharmony_ci
36068c2ecf20Sopenharmony_ci			/* unswap as u32 */
36078c2ecf20Sopenharmony_ci			mem_bswap_32(&header->adds_features,
36088c2ecf20Sopenharmony_ci				    BITS_TO_U32(HEADER_FEAT_BITS));
36098c2ecf20Sopenharmony_ci		}
36108c2ecf20Sopenharmony_ci
36118c2ecf20Sopenharmony_ci		if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
36128c2ecf20Sopenharmony_ci			bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
36138c2ecf20Sopenharmony_ci			set_bit(HEADER_BUILD_ID, header->adds_features);
36148c2ecf20Sopenharmony_ci		}
36158c2ecf20Sopenharmony_ci	}
36168c2ecf20Sopenharmony_ci
36178c2ecf20Sopenharmony_ci	memcpy(&ph->adds_features, &header->adds_features,
36188c2ecf20Sopenharmony_ci	       sizeof(ph->adds_features));
36198c2ecf20Sopenharmony_ci
36208c2ecf20Sopenharmony_ci	ph->data_offset  = header->data.offset;
36218c2ecf20Sopenharmony_ci	ph->data_size	 = header->data.size;
36228c2ecf20Sopenharmony_ci	ph->feat_offset  = header->data.offset + header->data.size;
36238c2ecf20Sopenharmony_ci	return 0;
36248c2ecf20Sopenharmony_ci}
36258c2ecf20Sopenharmony_ci
36268c2ecf20Sopenharmony_cistatic int perf_file_section__process(struct perf_file_section *section,
36278c2ecf20Sopenharmony_ci				      struct perf_header *ph,
36288c2ecf20Sopenharmony_ci				      int feat, int fd, void *data)
36298c2ecf20Sopenharmony_ci{
36308c2ecf20Sopenharmony_ci	struct feat_fd fdd = {
36318c2ecf20Sopenharmony_ci		.fd	= fd,
36328c2ecf20Sopenharmony_ci		.ph	= ph,
36338c2ecf20Sopenharmony_ci		.size	= section->size,
36348c2ecf20Sopenharmony_ci		.offset	= section->offset,
36358c2ecf20Sopenharmony_ci	};
36368c2ecf20Sopenharmony_ci
36378c2ecf20Sopenharmony_ci	if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
36388c2ecf20Sopenharmony_ci		pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
36398c2ecf20Sopenharmony_ci			  "%d, continuing...\n", section->offset, feat);
36408c2ecf20Sopenharmony_ci		return 0;
36418c2ecf20Sopenharmony_ci	}
36428c2ecf20Sopenharmony_ci
36438c2ecf20Sopenharmony_ci	if (feat >= HEADER_LAST_FEATURE) {
36448c2ecf20Sopenharmony_ci		pr_debug("unknown feature %d, continuing...\n", feat);
36458c2ecf20Sopenharmony_ci		return 0;
36468c2ecf20Sopenharmony_ci	}
36478c2ecf20Sopenharmony_ci
36488c2ecf20Sopenharmony_ci	if (!feat_ops[feat].process)
36498c2ecf20Sopenharmony_ci		return 0;
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci	return feat_ops[feat].process(&fdd, data);
36528c2ecf20Sopenharmony_ci}
36538c2ecf20Sopenharmony_ci
36548c2ecf20Sopenharmony_cistatic int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
36558c2ecf20Sopenharmony_ci				       struct perf_header *ph, int fd,
36568c2ecf20Sopenharmony_ci				       bool repipe)
36578c2ecf20Sopenharmony_ci{
36588c2ecf20Sopenharmony_ci	struct feat_fd ff = {
36598c2ecf20Sopenharmony_ci		.fd = STDOUT_FILENO,
36608c2ecf20Sopenharmony_ci		.ph = ph,
36618c2ecf20Sopenharmony_ci	};
36628c2ecf20Sopenharmony_ci	ssize_t ret;
36638c2ecf20Sopenharmony_ci
36648c2ecf20Sopenharmony_ci	ret = readn(fd, header, sizeof(*header));
36658c2ecf20Sopenharmony_ci	if (ret <= 0)
36668c2ecf20Sopenharmony_ci		return -1;
36678c2ecf20Sopenharmony_ci
36688c2ecf20Sopenharmony_ci	if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
36698c2ecf20Sopenharmony_ci		pr_debug("endian/magic failed\n");
36708c2ecf20Sopenharmony_ci		return -1;
36718c2ecf20Sopenharmony_ci	}
36728c2ecf20Sopenharmony_ci
36738c2ecf20Sopenharmony_ci	if (ph->needs_swap)
36748c2ecf20Sopenharmony_ci		header->size = bswap_64(header->size);
36758c2ecf20Sopenharmony_ci
36768c2ecf20Sopenharmony_ci	if (repipe && do_write(&ff, header, sizeof(*header)) < 0)
36778c2ecf20Sopenharmony_ci		return -1;
36788c2ecf20Sopenharmony_ci
36798c2ecf20Sopenharmony_ci	return 0;
36808c2ecf20Sopenharmony_ci}
36818c2ecf20Sopenharmony_ci
36828c2ecf20Sopenharmony_cistatic int perf_header__read_pipe(struct perf_session *session)
36838c2ecf20Sopenharmony_ci{
36848c2ecf20Sopenharmony_ci	struct perf_header *header = &session->header;
36858c2ecf20Sopenharmony_ci	struct perf_pipe_file_header f_header;
36868c2ecf20Sopenharmony_ci
36878c2ecf20Sopenharmony_ci	if (perf_file_header__read_pipe(&f_header, header,
36888c2ecf20Sopenharmony_ci					perf_data__fd(session->data),
36898c2ecf20Sopenharmony_ci					session->repipe) < 0) {
36908c2ecf20Sopenharmony_ci		pr_debug("incompatible file format\n");
36918c2ecf20Sopenharmony_ci		return -EINVAL;
36928c2ecf20Sopenharmony_ci	}
36938c2ecf20Sopenharmony_ci
36948c2ecf20Sopenharmony_ci	return f_header.size == sizeof(f_header) ? 0 : -1;
36958c2ecf20Sopenharmony_ci}
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_cistatic int read_attr(int fd, struct perf_header *ph,
36988c2ecf20Sopenharmony_ci		     struct perf_file_attr *f_attr)
36998c2ecf20Sopenharmony_ci{
37008c2ecf20Sopenharmony_ci	struct perf_event_attr *attr = &f_attr->attr;
37018c2ecf20Sopenharmony_ci	size_t sz, left;
37028c2ecf20Sopenharmony_ci	size_t our_sz = sizeof(f_attr->attr);
37038c2ecf20Sopenharmony_ci	ssize_t ret;
37048c2ecf20Sopenharmony_ci
37058c2ecf20Sopenharmony_ci	memset(f_attr, 0, sizeof(*f_attr));
37068c2ecf20Sopenharmony_ci
37078c2ecf20Sopenharmony_ci	/* read minimal guaranteed structure */
37088c2ecf20Sopenharmony_ci	ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
37098c2ecf20Sopenharmony_ci	if (ret <= 0) {
37108c2ecf20Sopenharmony_ci		pr_debug("cannot read %d bytes of header attr\n",
37118c2ecf20Sopenharmony_ci			 PERF_ATTR_SIZE_VER0);
37128c2ecf20Sopenharmony_ci		return -1;
37138c2ecf20Sopenharmony_ci	}
37148c2ecf20Sopenharmony_ci
37158c2ecf20Sopenharmony_ci	/* on file perf_event_attr size */
37168c2ecf20Sopenharmony_ci	sz = attr->size;
37178c2ecf20Sopenharmony_ci
37188c2ecf20Sopenharmony_ci	if (ph->needs_swap)
37198c2ecf20Sopenharmony_ci		sz = bswap_32(sz);
37208c2ecf20Sopenharmony_ci
37218c2ecf20Sopenharmony_ci	if (sz == 0) {
37228c2ecf20Sopenharmony_ci		/* assume ABI0 */
37238c2ecf20Sopenharmony_ci		sz =  PERF_ATTR_SIZE_VER0;
37248c2ecf20Sopenharmony_ci	} else if (sz > our_sz) {
37258c2ecf20Sopenharmony_ci		pr_debug("file uses a more recent and unsupported ABI"
37268c2ecf20Sopenharmony_ci			 " (%zu bytes extra)\n", sz - our_sz);
37278c2ecf20Sopenharmony_ci		return -1;
37288c2ecf20Sopenharmony_ci	}
37298c2ecf20Sopenharmony_ci	/* what we have not yet read and that we know about */
37308c2ecf20Sopenharmony_ci	left = sz - PERF_ATTR_SIZE_VER0;
37318c2ecf20Sopenharmony_ci	if (left) {
37328c2ecf20Sopenharmony_ci		void *ptr = attr;
37338c2ecf20Sopenharmony_ci		ptr += PERF_ATTR_SIZE_VER0;
37348c2ecf20Sopenharmony_ci
37358c2ecf20Sopenharmony_ci		ret = readn(fd, ptr, left);
37368c2ecf20Sopenharmony_ci	}
37378c2ecf20Sopenharmony_ci	/* read perf_file_section, ids are read in caller */
37388c2ecf20Sopenharmony_ci	ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));
37398c2ecf20Sopenharmony_ci
37408c2ecf20Sopenharmony_ci	return ret <= 0 ? -1 : 0;
37418c2ecf20Sopenharmony_ci}
37428c2ecf20Sopenharmony_ci
37438c2ecf20Sopenharmony_cistatic int perf_evsel__prepare_tracepoint_event(struct evsel *evsel,
37448c2ecf20Sopenharmony_ci						struct tep_handle *pevent)
37458c2ecf20Sopenharmony_ci{
37468c2ecf20Sopenharmony_ci	struct tep_event *event;
37478c2ecf20Sopenharmony_ci	char bf[128];
37488c2ecf20Sopenharmony_ci
37498c2ecf20Sopenharmony_ci	/* already prepared */
37508c2ecf20Sopenharmony_ci	if (evsel->tp_format)
37518c2ecf20Sopenharmony_ci		return 0;
37528c2ecf20Sopenharmony_ci
37538c2ecf20Sopenharmony_ci	if (pevent == NULL) {
37548c2ecf20Sopenharmony_ci		pr_debug("broken or missing trace data\n");
37558c2ecf20Sopenharmony_ci		return -1;
37568c2ecf20Sopenharmony_ci	}
37578c2ecf20Sopenharmony_ci
37588c2ecf20Sopenharmony_ci	event = tep_find_event(pevent, evsel->core.attr.config);
37598c2ecf20Sopenharmony_ci	if (event == NULL) {
37608c2ecf20Sopenharmony_ci		pr_debug("cannot find event format for %d\n", (int)evsel->core.attr.config);
37618c2ecf20Sopenharmony_ci		return -1;
37628c2ecf20Sopenharmony_ci	}
37638c2ecf20Sopenharmony_ci
37648c2ecf20Sopenharmony_ci	if (!evsel->name) {
37658c2ecf20Sopenharmony_ci		snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
37668c2ecf20Sopenharmony_ci		evsel->name = strdup(bf);
37678c2ecf20Sopenharmony_ci		if (evsel->name == NULL)
37688c2ecf20Sopenharmony_ci			return -1;
37698c2ecf20Sopenharmony_ci	}
37708c2ecf20Sopenharmony_ci
37718c2ecf20Sopenharmony_ci	evsel->tp_format = event;
37728c2ecf20Sopenharmony_ci	return 0;
37738c2ecf20Sopenharmony_ci}
37748c2ecf20Sopenharmony_ci
37758c2ecf20Sopenharmony_cistatic int perf_evlist__prepare_tracepoint_events(struct evlist *evlist,
37768c2ecf20Sopenharmony_ci						  struct tep_handle *pevent)
37778c2ecf20Sopenharmony_ci{
37788c2ecf20Sopenharmony_ci	struct evsel *pos;
37798c2ecf20Sopenharmony_ci
37808c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
37818c2ecf20Sopenharmony_ci		if (pos->core.attr.type == PERF_TYPE_TRACEPOINT &&
37828c2ecf20Sopenharmony_ci		    perf_evsel__prepare_tracepoint_event(pos, pevent))
37838c2ecf20Sopenharmony_ci			return -1;
37848c2ecf20Sopenharmony_ci	}
37858c2ecf20Sopenharmony_ci
37868c2ecf20Sopenharmony_ci	return 0;
37878c2ecf20Sopenharmony_ci}
37888c2ecf20Sopenharmony_ci
37898c2ecf20Sopenharmony_ciint perf_session__read_header(struct perf_session *session)
37908c2ecf20Sopenharmony_ci{
37918c2ecf20Sopenharmony_ci	struct perf_data *data = session->data;
37928c2ecf20Sopenharmony_ci	struct perf_header *header = &session->header;
37938c2ecf20Sopenharmony_ci	struct perf_file_header	f_header;
37948c2ecf20Sopenharmony_ci	struct perf_file_attr	f_attr;
37958c2ecf20Sopenharmony_ci	u64			f_id;
37968c2ecf20Sopenharmony_ci	int nr_attrs, nr_ids, i, j, err;
37978c2ecf20Sopenharmony_ci	int fd = perf_data__fd(data);
37988c2ecf20Sopenharmony_ci
37998c2ecf20Sopenharmony_ci	session->evlist = evlist__new();
38008c2ecf20Sopenharmony_ci	if (session->evlist == NULL)
38018c2ecf20Sopenharmony_ci		return -ENOMEM;
38028c2ecf20Sopenharmony_ci
38038c2ecf20Sopenharmony_ci	session->evlist->env = &header->env;
38048c2ecf20Sopenharmony_ci	session->machines.host.env = &header->env;
38058c2ecf20Sopenharmony_ci
38068c2ecf20Sopenharmony_ci	/*
38078c2ecf20Sopenharmony_ci	 * We can read 'pipe' data event from regular file,
38088c2ecf20Sopenharmony_ci	 * check for the pipe header regardless of source.
38098c2ecf20Sopenharmony_ci	 */
38108c2ecf20Sopenharmony_ci	err = perf_header__read_pipe(session);
38118c2ecf20Sopenharmony_ci	if (!err || (err && perf_data__is_pipe(data))) {
38128c2ecf20Sopenharmony_ci		data->is_pipe = true;
38138c2ecf20Sopenharmony_ci		return err;
38148c2ecf20Sopenharmony_ci	}
38158c2ecf20Sopenharmony_ci
38168c2ecf20Sopenharmony_ci	if (perf_file_header__read(&f_header, header, fd) < 0)
38178c2ecf20Sopenharmony_ci		return -EINVAL;
38188c2ecf20Sopenharmony_ci
38198c2ecf20Sopenharmony_ci	/*
38208c2ecf20Sopenharmony_ci	 * Sanity check that perf.data was written cleanly; data size is
38218c2ecf20Sopenharmony_ci	 * initialized to 0 and updated only if the on_exit function is run.
38228c2ecf20Sopenharmony_ci	 * If data size is still 0 then the file contains only partial
38238c2ecf20Sopenharmony_ci	 * information.  Just warn user and process it as much as it can.
38248c2ecf20Sopenharmony_ci	 */
38258c2ecf20Sopenharmony_ci	if (f_header.data.size == 0) {
38268c2ecf20Sopenharmony_ci		pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
38278c2ecf20Sopenharmony_ci			   "Was the 'perf record' command properly terminated?\n",
38288c2ecf20Sopenharmony_ci			   data->file.path);
38298c2ecf20Sopenharmony_ci	}
38308c2ecf20Sopenharmony_ci
38318c2ecf20Sopenharmony_ci	if (f_header.attr_size == 0) {
38328c2ecf20Sopenharmony_ci		pr_err("ERROR: The %s file's attr size field is 0 which is unexpected.\n"
38338c2ecf20Sopenharmony_ci		       "Was the 'perf record' command properly terminated?\n",
38348c2ecf20Sopenharmony_ci		       data->file.path);
38358c2ecf20Sopenharmony_ci		return -EINVAL;
38368c2ecf20Sopenharmony_ci	}
38378c2ecf20Sopenharmony_ci
38388c2ecf20Sopenharmony_ci	nr_attrs = f_header.attrs.size / f_header.attr_size;
38398c2ecf20Sopenharmony_ci	lseek(fd, f_header.attrs.offset, SEEK_SET);
38408c2ecf20Sopenharmony_ci
38418c2ecf20Sopenharmony_ci	for (i = 0; i < nr_attrs; i++) {
38428c2ecf20Sopenharmony_ci		struct evsel *evsel;
38438c2ecf20Sopenharmony_ci		off_t tmp;
38448c2ecf20Sopenharmony_ci
38458c2ecf20Sopenharmony_ci		if (read_attr(fd, header, &f_attr) < 0)
38468c2ecf20Sopenharmony_ci			goto out_errno;
38478c2ecf20Sopenharmony_ci
38488c2ecf20Sopenharmony_ci		if (header->needs_swap) {
38498c2ecf20Sopenharmony_ci			f_attr.ids.size   = bswap_64(f_attr.ids.size);
38508c2ecf20Sopenharmony_ci			f_attr.ids.offset = bswap_64(f_attr.ids.offset);
38518c2ecf20Sopenharmony_ci			perf_event__attr_swap(&f_attr.attr);
38528c2ecf20Sopenharmony_ci		}
38538c2ecf20Sopenharmony_ci
38548c2ecf20Sopenharmony_ci		tmp = lseek(fd, 0, SEEK_CUR);
38558c2ecf20Sopenharmony_ci		evsel = evsel__new(&f_attr.attr);
38568c2ecf20Sopenharmony_ci
38578c2ecf20Sopenharmony_ci		if (evsel == NULL)
38588c2ecf20Sopenharmony_ci			goto out_delete_evlist;
38598c2ecf20Sopenharmony_ci
38608c2ecf20Sopenharmony_ci		evsel->needs_swap = header->needs_swap;
38618c2ecf20Sopenharmony_ci		/*
38628c2ecf20Sopenharmony_ci		 * Do it before so that if perf_evsel__alloc_id fails, this
38638c2ecf20Sopenharmony_ci		 * entry gets purged too at evlist__delete().
38648c2ecf20Sopenharmony_ci		 */
38658c2ecf20Sopenharmony_ci		evlist__add(session->evlist, evsel);
38668c2ecf20Sopenharmony_ci
38678c2ecf20Sopenharmony_ci		nr_ids = f_attr.ids.size / sizeof(u64);
38688c2ecf20Sopenharmony_ci		/*
38698c2ecf20Sopenharmony_ci		 * We don't have the cpu and thread maps on the header, so
38708c2ecf20Sopenharmony_ci		 * for allocating the perf_sample_id table we fake 1 cpu and
38718c2ecf20Sopenharmony_ci		 * hattr->ids threads.
38728c2ecf20Sopenharmony_ci		 */
38738c2ecf20Sopenharmony_ci		if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
38748c2ecf20Sopenharmony_ci			goto out_delete_evlist;
38758c2ecf20Sopenharmony_ci
38768c2ecf20Sopenharmony_ci		lseek(fd, f_attr.ids.offset, SEEK_SET);
38778c2ecf20Sopenharmony_ci
38788c2ecf20Sopenharmony_ci		for (j = 0; j < nr_ids; j++) {
38798c2ecf20Sopenharmony_ci			if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
38808c2ecf20Sopenharmony_ci				goto out_errno;
38818c2ecf20Sopenharmony_ci
38828c2ecf20Sopenharmony_ci			perf_evlist__id_add(&session->evlist->core, &evsel->core, 0, j, f_id);
38838c2ecf20Sopenharmony_ci		}
38848c2ecf20Sopenharmony_ci
38858c2ecf20Sopenharmony_ci		lseek(fd, tmp, SEEK_SET);
38868c2ecf20Sopenharmony_ci	}
38878c2ecf20Sopenharmony_ci
38888c2ecf20Sopenharmony_ci	perf_header__process_sections(header, fd, &session->tevent,
38898c2ecf20Sopenharmony_ci				      perf_file_section__process);
38908c2ecf20Sopenharmony_ci
38918c2ecf20Sopenharmony_ci	if (perf_evlist__prepare_tracepoint_events(session->evlist,
38928c2ecf20Sopenharmony_ci						   session->tevent.pevent))
38938c2ecf20Sopenharmony_ci		goto out_delete_evlist;
38948c2ecf20Sopenharmony_ci
38958c2ecf20Sopenharmony_ci	return 0;
38968c2ecf20Sopenharmony_ciout_errno:
38978c2ecf20Sopenharmony_ci	return -errno;
38988c2ecf20Sopenharmony_ci
38998c2ecf20Sopenharmony_ciout_delete_evlist:
39008c2ecf20Sopenharmony_ci	evlist__delete(session->evlist);
39018c2ecf20Sopenharmony_ci	session->evlist = NULL;
39028c2ecf20Sopenharmony_ci	return -ENOMEM;
39038c2ecf20Sopenharmony_ci}
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ciint perf_event__process_feature(struct perf_session *session,
39068c2ecf20Sopenharmony_ci				union perf_event *event)
39078c2ecf20Sopenharmony_ci{
39088c2ecf20Sopenharmony_ci	struct perf_tool *tool = session->tool;
39098c2ecf20Sopenharmony_ci	struct feat_fd ff = { .fd = 0 };
39108c2ecf20Sopenharmony_ci	struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event;
39118c2ecf20Sopenharmony_ci	int type = fe->header.type;
39128c2ecf20Sopenharmony_ci	u64 feat = fe->feat_id;
39138c2ecf20Sopenharmony_ci
39148c2ecf20Sopenharmony_ci	if (type < 0 || type >= PERF_RECORD_HEADER_MAX) {
39158c2ecf20Sopenharmony_ci		pr_warning("invalid record type %d in pipe-mode\n", type);
39168c2ecf20Sopenharmony_ci		return 0;
39178c2ecf20Sopenharmony_ci	}
39188c2ecf20Sopenharmony_ci	if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) {
39198c2ecf20Sopenharmony_ci		pr_warning("invalid record type %d in pipe-mode\n", type);
39208c2ecf20Sopenharmony_ci		return -1;
39218c2ecf20Sopenharmony_ci	}
39228c2ecf20Sopenharmony_ci
39238c2ecf20Sopenharmony_ci	if (!feat_ops[feat].process)
39248c2ecf20Sopenharmony_ci		return 0;
39258c2ecf20Sopenharmony_ci
39268c2ecf20Sopenharmony_ci	ff.buf  = (void *)fe->data;
39278c2ecf20Sopenharmony_ci	ff.size = event->header.size - sizeof(*fe);
39288c2ecf20Sopenharmony_ci	ff.ph = &session->header;
39298c2ecf20Sopenharmony_ci
39308c2ecf20Sopenharmony_ci	if (feat_ops[feat].process(&ff, NULL))
39318c2ecf20Sopenharmony_ci		return -1;
39328c2ecf20Sopenharmony_ci
39338c2ecf20Sopenharmony_ci	if (!feat_ops[feat].print || !tool->show_feat_hdr)
39348c2ecf20Sopenharmony_ci		return 0;
39358c2ecf20Sopenharmony_ci
39368c2ecf20Sopenharmony_ci	if (!feat_ops[feat].full_only ||
39378c2ecf20Sopenharmony_ci	    tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) {
39388c2ecf20Sopenharmony_ci		feat_ops[feat].print(&ff, stdout);
39398c2ecf20Sopenharmony_ci	} else {
39408c2ecf20Sopenharmony_ci		fprintf(stdout, "# %s info available, use -I to display\n",
39418c2ecf20Sopenharmony_ci			feat_ops[feat].name);
39428c2ecf20Sopenharmony_ci	}
39438c2ecf20Sopenharmony_ci
39448c2ecf20Sopenharmony_ci	return 0;
39458c2ecf20Sopenharmony_ci}
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_cisize_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
39488c2ecf20Sopenharmony_ci{
39498c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev = &event->event_update;
39508c2ecf20Sopenharmony_ci	struct perf_record_event_update_scale *ev_scale;
39518c2ecf20Sopenharmony_ci	struct perf_record_event_update_cpus *ev_cpus;
39528c2ecf20Sopenharmony_ci	struct perf_cpu_map *map;
39538c2ecf20Sopenharmony_ci	size_t ret;
39548c2ecf20Sopenharmony_ci
39558c2ecf20Sopenharmony_ci	ret = fprintf(fp, "\n... id:    %" PRI_lu64 "\n", ev->id);
39568c2ecf20Sopenharmony_ci
39578c2ecf20Sopenharmony_ci	switch (ev->type) {
39588c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__SCALE:
39598c2ecf20Sopenharmony_ci		ev_scale = (struct perf_record_event_update_scale *)ev->data;
39608c2ecf20Sopenharmony_ci		ret += fprintf(fp, "... scale: %f\n", ev_scale->scale);
39618c2ecf20Sopenharmony_ci		break;
39628c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__UNIT:
39638c2ecf20Sopenharmony_ci		ret += fprintf(fp, "... unit:  %s\n", ev->data);
39648c2ecf20Sopenharmony_ci		break;
39658c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__NAME:
39668c2ecf20Sopenharmony_ci		ret += fprintf(fp, "... name:  %s\n", ev->data);
39678c2ecf20Sopenharmony_ci		break;
39688c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__CPUS:
39698c2ecf20Sopenharmony_ci		ev_cpus = (struct perf_record_event_update_cpus *)ev->data;
39708c2ecf20Sopenharmony_ci		ret += fprintf(fp, "... ");
39718c2ecf20Sopenharmony_ci
39728c2ecf20Sopenharmony_ci		map = cpu_map__new_data(&ev_cpus->cpus);
39738c2ecf20Sopenharmony_ci		if (map)
39748c2ecf20Sopenharmony_ci			ret += cpu_map__fprintf(map, fp);
39758c2ecf20Sopenharmony_ci		else
39768c2ecf20Sopenharmony_ci			ret += fprintf(fp, "failed to get cpus\n");
39778c2ecf20Sopenharmony_ci		break;
39788c2ecf20Sopenharmony_ci	default:
39798c2ecf20Sopenharmony_ci		ret += fprintf(fp, "... unknown type\n");
39808c2ecf20Sopenharmony_ci		break;
39818c2ecf20Sopenharmony_ci	}
39828c2ecf20Sopenharmony_ci
39838c2ecf20Sopenharmony_ci	return ret;
39848c2ecf20Sopenharmony_ci}
39858c2ecf20Sopenharmony_ci
39868c2ecf20Sopenharmony_ciint perf_event__process_attr(struct perf_tool *tool __maybe_unused,
39878c2ecf20Sopenharmony_ci			     union perf_event *event,
39888c2ecf20Sopenharmony_ci			     struct evlist **pevlist)
39898c2ecf20Sopenharmony_ci{
39908c2ecf20Sopenharmony_ci	u32 i, n_ids;
39918c2ecf20Sopenharmony_ci	u64 *ids;
39928c2ecf20Sopenharmony_ci	struct evsel *evsel;
39938c2ecf20Sopenharmony_ci	struct evlist *evlist = *pevlist;
39948c2ecf20Sopenharmony_ci
39958c2ecf20Sopenharmony_ci	if (evlist == NULL) {
39968c2ecf20Sopenharmony_ci		*pevlist = evlist = evlist__new();
39978c2ecf20Sopenharmony_ci		if (evlist == NULL)
39988c2ecf20Sopenharmony_ci			return -ENOMEM;
39998c2ecf20Sopenharmony_ci	}
40008c2ecf20Sopenharmony_ci
40018c2ecf20Sopenharmony_ci	evsel = evsel__new(&event->attr.attr);
40028c2ecf20Sopenharmony_ci	if (evsel == NULL)
40038c2ecf20Sopenharmony_ci		return -ENOMEM;
40048c2ecf20Sopenharmony_ci
40058c2ecf20Sopenharmony_ci	evlist__add(evlist, evsel);
40068c2ecf20Sopenharmony_ci
40078c2ecf20Sopenharmony_ci	n_ids = event->header.size - sizeof(event->header) - event->attr.attr.size;
40088c2ecf20Sopenharmony_ci	n_ids = n_ids / sizeof(u64);
40098c2ecf20Sopenharmony_ci	/*
40108c2ecf20Sopenharmony_ci	 * We don't have the cpu and thread maps on the header, so
40118c2ecf20Sopenharmony_ci	 * for allocating the perf_sample_id table we fake 1 cpu and
40128c2ecf20Sopenharmony_ci	 * hattr->ids threads.
40138c2ecf20Sopenharmony_ci	 */
40148c2ecf20Sopenharmony_ci	if (perf_evsel__alloc_id(&evsel->core, 1, n_ids))
40158c2ecf20Sopenharmony_ci		return -ENOMEM;
40168c2ecf20Sopenharmony_ci
40178c2ecf20Sopenharmony_ci	ids = (void *)&event->attr.attr + event->attr.attr.size;
40188c2ecf20Sopenharmony_ci	for (i = 0; i < n_ids; i++) {
40198c2ecf20Sopenharmony_ci		perf_evlist__id_add(&evlist->core, &evsel->core, 0, i, ids[i]);
40208c2ecf20Sopenharmony_ci	}
40218c2ecf20Sopenharmony_ci
40228c2ecf20Sopenharmony_ci	return 0;
40238c2ecf20Sopenharmony_ci}
40248c2ecf20Sopenharmony_ci
40258c2ecf20Sopenharmony_ciint perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
40268c2ecf20Sopenharmony_ci				     union perf_event *event,
40278c2ecf20Sopenharmony_ci				     struct evlist **pevlist)
40288c2ecf20Sopenharmony_ci{
40298c2ecf20Sopenharmony_ci	struct perf_record_event_update *ev = &event->event_update;
40308c2ecf20Sopenharmony_ci	struct perf_record_event_update_scale *ev_scale;
40318c2ecf20Sopenharmony_ci	struct perf_record_event_update_cpus *ev_cpus;
40328c2ecf20Sopenharmony_ci	struct evlist *evlist;
40338c2ecf20Sopenharmony_ci	struct evsel *evsel;
40348c2ecf20Sopenharmony_ci	struct perf_cpu_map *map;
40358c2ecf20Sopenharmony_ci
40368c2ecf20Sopenharmony_ci	if (!pevlist || *pevlist == NULL)
40378c2ecf20Sopenharmony_ci		return -EINVAL;
40388c2ecf20Sopenharmony_ci
40398c2ecf20Sopenharmony_ci	evlist = *pevlist;
40408c2ecf20Sopenharmony_ci
40418c2ecf20Sopenharmony_ci	evsel = perf_evlist__id2evsel(evlist, ev->id);
40428c2ecf20Sopenharmony_ci	if (evsel == NULL)
40438c2ecf20Sopenharmony_ci		return -EINVAL;
40448c2ecf20Sopenharmony_ci
40458c2ecf20Sopenharmony_ci	switch (ev->type) {
40468c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__UNIT:
40478c2ecf20Sopenharmony_ci		evsel->unit = strdup(ev->data);
40488c2ecf20Sopenharmony_ci		break;
40498c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__NAME:
40508c2ecf20Sopenharmony_ci		evsel->name = strdup(ev->data);
40518c2ecf20Sopenharmony_ci		break;
40528c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__SCALE:
40538c2ecf20Sopenharmony_ci		ev_scale = (struct perf_record_event_update_scale *)ev->data;
40548c2ecf20Sopenharmony_ci		evsel->scale = ev_scale->scale;
40558c2ecf20Sopenharmony_ci		break;
40568c2ecf20Sopenharmony_ci	case PERF_EVENT_UPDATE__CPUS:
40578c2ecf20Sopenharmony_ci		ev_cpus = (struct perf_record_event_update_cpus *)ev->data;
40588c2ecf20Sopenharmony_ci
40598c2ecf20Sopenharmony_ci		map = cpu_map__new_data(&ev_cpus->cpus);
40608c2ecf20Sopenharmony_ci		if (map)
40618c2ecf20Sopenharmony_ci			evsel->core.own_cpus = map;
40628c2ecf20Sopenharmony_ci		else
40638c2ecf20Sopenharmony_ci			pr_err("failed to get event_update cpus\n");
40648c2ecf20Sopenharmony_ci	default:
40658c2ecf20Sopenharmony_ci		break;
40668c2ecf20Sopenharmony_ci	}
40678c2ecf20Sopenharmony_ci
40688c2ecf20Sopenharmony_ci	return 0;
40698c2ecf20Sopenharmony_ci}
40708c2ecf20Sopenharmony_ci
40718c2ecf20Sopenharmony_ciint perf_event__process_tracing_data(struct perf_session *session,
40728c2ecf20Sopenharmony_ci				     union perf_event *event)
40738c2ecf20Sopenharmony_ci{
40748c2ecf20Sopenharmony_ci	ssize_t size_read, padding, size = event->tracing_data.size;
40758c2ecf20Sopenharmony_ci	int fd = perf_data__fd(session->data);
40768c2ecf20Sopenharmony_ci	char buf[BUFSIZ];
40778c2ecf20Sopenharmony_ci
40788c2ecf20Sopenharmony_ci	/*
40798c2ecf20Sopenharmony_ci	 * The pipe fd is already in proper place and in any case
40808c2ecf20Sopenharmony_ci	 * we can't move it, and we'd screw the case where we read
40818c2ecf20Sopenharmony_ci	 * 'pipe' data from regular file. The trace_report reads
40828c2ecf20Sopenharmony_ci	 * data from 'fd' so we need to set it directly behind the
40838c2ecf20Sopenharmony_ci	 * event, where the tracing data starts.
40848c2ecf20Sopenharmony_ci	 */
40858c2ecf20Sopenharmony_ci	if (!perf_data__is_pipe(session->data)) {
40868c2ecf20Sopenharmony_ci		off_t offset = lseek(fd, 0, SEEK_CUR);
40878c2ecf20Sopenharmony_ci
40888c2ecf20Sopenharmony_ci		/* setup for reading amidst mmap */
40898c2ecf20Sopenharmony_ci		lseek(fd, offset + sizeof(struct perf_record_header_tracing_data),
40908c2ecf20Sopenharmony_ci		      SEEK_SET);
40918c2ecf20Sopenharmony_ci	}
40928c2ecf20Sopenharmony_ci
40938c2ecf20Sopenharmony_ci	size_read = trace_report(fd, &session->tevent,
40948c2ecf20Sopenharmony_ci				 session->repipe);
40958c2ecf20Sopenharmony_ci	padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
40968c2ecf20Sopenharmony_ci
40978c2ecf20Sopenharmony_ci	if (readn(fd, buf, padding) < 0) {
40988c2ecf20Sopenharmony_ci		pr_err("%s: reading input file", __func__);
40998c2ecf20Sopenharmony_ci		return -1;
41008c2ecf20Sopenharmony_ci	}
41018c2ecf20Sopenharmony_ci	if (session->repipe) {
41028c2ecf20Sopenharmony_ci		int retw = write(STDOUT_FILENO, buf, padding);
41038c2ecf20Sopenharmony_ci		if (retw <= 0 || retw != padding) {
41048c2ecf20Sopenharmony_ci			pr_err("%s: repiping tracing data padding", __func__);
41058c2ecf20Sopenharmony_ci			return -1;
41068c2ecf20Sopenharmony_ci		}
41078c2ecf20Sopenharmony_ci	}
41088c2ecf20Sopenharmony_ci
41098c2ecf20Sopenharmony_ci	if (size_read + padding != size) {
41108c2ecf20Sopenharmony_ci		pr_err("%s: tracing data size mismatch", __func__);
41118c2ecf20Sopenharmony_ci		return -1;
41128c2ecf20Sopenharmony_ci	}
41138c2ecf20Sopenharmony_ci
41148c2ecf20Sopenharmony_ci	perf_evlist__prepare_tracepoint_events(session->evlist,
41158c2ecf20Sopenharmony_ci					       session->tevent.pevent);
41168c2ecf20Sopenharmony_ci
41178c2ecf20Sopenharmony_ci	return size_read + padding;
41188c2ecf20Sopenharmony_ci}
41198c2ecf20Sopenharmony_ci
41208c2ecf20Sopenharmony_ciint perf_event__process_build_id(struct perf_session *session,
41218c2ecf20Sopenharmony_ci				 union perf_event *event)
41228c2ecf20Sopenharmony_ci{
41238c2ecf20Sopenharmony_ci	__event_process_build_id(&event->build_id,
41248c2ecf20Sopenharmony_ci				 event->build_id.filename,
41258c2ecf20Sopenharmony_ci				 session);
41268c2ecf20Sopenharmony_ci	return 0;
41278c2ecf20Sopenharmony_ci}
4128