162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <errno.h>
362306a36Sopenharmony_ci#include <inttypes.h>
462306a36Sopenharmony_ci#include "string2.h"
562306a36Sopenharmony_ci#include <sys/param.h>
662306a36Sopenharmony_ci#include <sys/types.h>
762306a36Sopenharmony_ci#include <byteswap.h>
862306a36Sopenharmony_ci#include <unistd.h>
962306a36Sopenharmony_ci#include <regex.h>
1062306a36Sopenharmony_ci#include <stdio.h>
1162306a36Sopenharmony_ci#include <stdlib.h>
1262306a36Sopenharmony_ci#include <linux/compiler.h>
1362306a36Sopenharmony_ci#include <linux/list.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/bitops.h>
1662306a36Sopenharmony_ci#include <linux/string.h>
1762306a36Sopenharmony_ci#include <linux/stringify.h>
1862306a36Sopenharmony_ci#include <linux/zalloc.h>
1962306a36Sopenharmony_ci#include <sys/stat.h>
2062306a36Sopenharmony_ci#include <sys/utsname.h>
2162306a36Sopenharmony_ci#include <linux/time64.h>
2262306a36Sopenharmony_ci#include <dirent.h>
2362306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
2462306a36Sopenharmony_ci#include <bpf/libbpf.h>
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci#include <perf/cpumap.h>
2762306a36Sopenharmony_ci#include <tools/libc_compat.h> // reallocarray
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "dso.h"
3062306a36Sopenharmony_ci#include "evlist.h"
3162306a36Sopenharmony_ci#include "evsel.h"
3262306a36Sopenharmony_ci#include "util/evsel_fprintf.h"
3362306a36Sopenharmony_ci#include "header.h"
3462306a36Sopenharmony_ci#include "memswap.h"
3562306a36Sopenharmony_ci#include "trace-event.h"
3662306a36Sopenharmony_ci#include "session.h"
3762306a36Sopenharmony_ci#include "symbol.h"
3862306a36Sopenharmony_ci#include "debug.h"
3962306a36Sopenharmony_ci#include "cpumap.h"
4062306a36Sopenharmony_ci#include "pmu.h"
4162306a36Sopenharmony_ci#include "pmus.h"
4262306a36Sopenharmony_ci#include "vdso.h"
4362306a36Sopenharmony_ci#include "strbuf.h"
4462306a36Sopenharmony_ci#include "build-id.h"
4562306a36Sopenharmony_ci#include "data.h"
4662306a36Sopenharmony_ci#include <api/fs/fs.h>
4762306a36Sopenharmony_ci#include "asm/bug.h"
4862306a36Sopenharmony_ci#include "tool.h"
4962306a36Sopenharmony_ci#include "time-utils.h"
5062306a36Sopenharmony_ci#include "units.h"
5162306a36Sopenharmony_ci#include "util/util.h" // perf_exe()
5262306a36Sopenharmony_ci#include "cputopo.h"
5362306a36Sopenharmony_ci#include "bpf-event.h"
5462306a36Sopenharmony_ci#include "bpf-utils.h"
5562306a36Sopenharmony_ci#include "clockid.h"
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#include <linux/ctype.h>
5862306a36Sopenharmony_ci#include <internal/lib.h>
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
6162306a36Sopenharmony_ci#include <traceevent/event-parse.h>
6262306a36Sopenharmony_ci#endif
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/*
6562306a36Sopenharmony_ci * magic2 = "PERFILE2"
6662306a36Sopenharmony_ci * must be a numerical value to let the endianness
6762306a36Sopenharmony_ci * determine the memory layout. That way we are able
6862306a36Sopenharmony_ci * to detect endianness when reading the perf.data file
6962306a36Sopenharmony_ci * back.
7062306a36Sopenharmony_ci *
7162306a36Sopenharmony_ci * we check for legacy (PERFFILE) format.
7262306a36Sopenharmony_ci */
7362306a36Sopenharmony_cistatic const char *__perf_magic1 = "PERFFILE";
7462306a36Sopenharmony_cistatic const u64 __perf_magic2    = 0x32454c4946524550ULL;
7562306a36Sopenharmony_cistatic const u64 __perf_magic2_sw = 0x50455246494c4532ULL;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define PERF_MAGIC	__perf_magic2
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciconst char perf_version_string[] = PERF_VERSION;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_cistruct perf_file_attr {
8262306a36Sopenharmony_ci	struct perf_event_attr	attr;
8362306a36Sopenharmony_ci	struct perf_file_section	ids;
8462306a36Sopenharmony_ci};
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_civoid perf_header__set_feat(struct perf_header *header, int feat)
8762306a36Sopenharmony_ci{
8862306a36Sopenharmony_ci	__set_bit(feat, header->adds_features);
8962306a36Sopenharmony_ci}
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_civoid perf_header__clear_feat(struct perf_header *header, int feat)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	__clear_bit(feat, header->adds_features);
9462306a36Sopenharmony_ci}
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cibool perf_header__has_feat(const struct perf_header *header, int feat)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	return test_bit(feat, header->adds_features);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic int __do_write_fd(struct feat_fd *ff, const void *buf, size_t size)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	ssize_t ret = writen(ff->fd, buf, size);
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (ret != (ssize_t)size)
10662306a36Sopenharmony_ci		return ret < 0 ? (int)ret : -1;
10762306a36Sopenharmony_ci	return 0;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic int __do_write_buf(struct feat_fd *ff,  const void *buf, size_t size)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	/* struct perf_event_header::size is u16 */
11362306a36Sopenharmony_ci	const size_t max_size = 0xffff - sizeof(struct perf_event_header);
11462306a36Sopenharmony_ci	size_t new_size = ff->size;
11562306a36Sopenharmony_ci	void *addr;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	if (size + ff->offset > max_size)
11862306a36Sopenharmony_ci		return -E2BIG;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	while (size > (new_size - ff->offset))
12162306a36Sopenharmony_ci		new_size <<= 1;
12262306a36Sopenharmony_ci	new_size = min(max_size, new_size);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	if (ff->size < new_size) {
12562306a36Sopenharmony_ci		addr = realloc(ff->buf, new_size);
12662306a36Sopenharmony_ci		if (!addr)
12762306a36Sopenharmony_ci			return -ENOMEM;
12862306a36Sopenharmony_ci		ff->buf = addr;
12962306a36Sopenharmony_ci		ff->size = new_size;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	memcpy(ff->buf + ff->offset, buf, size);
13362306a36Sopenharmony_ci	ff->offset += size;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */
13962306a36Sopenharmony_ciint do_write(struct feat_fd *ff, const void *buf, size_t size)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	if (!ff->buf)
14262306a36Sopenharmony_ci		return __do_write_fd(ff, buf, size);
14362306a36Sopenharmony_ci	return __do_write_buf(ff, buf, size);
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */
14762306a36Sopenharmony_cistatic int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	u64 *p = (u64 *) set;
15062306a36Sopenharmony_ci	int i, ret;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	ret = do_write(ff, &size, sizeof(size));
15362306a36Sopenharmony_ci	if (ret < 0)
15462306a36Sopenharmony_ci		return ret;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
15762306a36Sopenharmony_ci		ret = do_write(ff, p + i, sizeof(*p));
15862306a36Sopenharmony_ci		if (ret < 0)
15962306a36Sopenharmony_ci			return ret;
16062306a36Sopenharmony_ci	}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	return 0;
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */
16662306a36Sopenharmony_ciint write_padded(struct feat_fd *ff, const void *bf,
16762306a36Sopenharmony_ci		 size_t count, size_t count_aligned)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	static const char zero_buf[NAME_ALIGN];
17062306a36Sopenharmony_ci	int err = do_write(ff, bf, count);
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	if (!err)
17362306a36Sopenharmony_ci		err = do_write(ff, zero_buf, count_aligned - count);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return err;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci#define string_size(str)						\
17962306a36Sopenharmony_ci	(PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32))
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */
18262306a36Sopenharmony_cistatic int do_write_string(struct feat_fd *ff, const char *str)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	u32 len, olen;
18562306a36Sopenharmony_ci	int ret;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	olen = strlen(str) + 1;
18862306a36Sopenharmony_ci	len = PERF_ALIGN(olen, NAME_ALIGN);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* write len, incl. \0 */
19162306a36Sopenharmony_ci	ret = do_write(ff, &len, sizeof(len));
19262306a36Sopenharmony_ci	if (ret < 0)
19362306a36Sopenharmony_ci		return ret;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	return write_padded(ff, str, olen, len);
19662306a36Sopenharmony_ci}
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_cistatic int __do_read_fd(struct feat_fd *ff, void *addr, ssize_t size)
19962306a36Sopenharmony_ci{
20062306a36Sopenharmony_ci	ssize_t ret = readn(ff->fd, addr, size);
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (ret != size)
20362306a36Sopenharmony_ci		return ret < 0 ? (int)ret : -1;
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	if (size > (ssize_t)ff->size - ff->offset)
21062306a36Sopenharmony_ci		return -1;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	memcpy(addr, ff->buf + ff->offset, size);
21362306a36Sopenharmony_ci	ff->offset += size;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	return 0;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci}
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_cistatic int __do_read(struct feat_fd *ff, void *addr, ssize_t size)
22062306a36Sopenharmony_ci{
22162306a36Sopenharmony_ci	if (!ff->buf)
22262306a36Sopenharmony_ci		return __do_read_fd(ff, addr, size);
22362306a36Sopenharmony_ci	return __do_read_buf(ff, addr, size);
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic int do_read_u32(struct feat_fd *ff, u32 *addr)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	int ret;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	ret = __do_read(ff, addr, sizeof(*addr));
23162306a36Sopenharmony_ci	if (ret)
23262306a36Sopenharmony_ci		return ret;
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	if (ff->ph->needs_swap)
23562306a36Sopenharmony_ci		*addr = bswap_32(*addr);
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic int do_read_u64(struct feat_fd *ff, u64 *addr)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int ret;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	ret = __do_read(ff, addr, sizeof(*addr));
24462306a36Sopenharmony_ci	if (ret)
24562306a36Sopenharmony_ci		return ret;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	if (ff->ph->needs_swap)
24862306a36Sopenharmony_ci		*addr = bswap_64(*addr);
24962306a36Sopenharmony_ci	return 0;
25062306a36Sopenharmony_ci}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_cistatic char *do_read_string(struct feat_fd *ff)
25362306a36Sopenharmony_ci{
25462306a36Sopenharmony_ci	u32 len;
25562306a36Sopenharmony_ci	char *buf;
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (do_read_u32(ff, &len))
25862306a36Sopenharmony_ci		return NULL;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	buf = malloc(len);
26162306a36Sopenharmony_ci	if (!buf)
26262306a36Sopenharmony_ci		return NULL;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (!__do_read(ff, buf, len)) {
26562306a36Sopenharmony_ci		/*
26662306a36Sopenharmony_ci		 * strings are padded by zeroes
26762306a36Sopenharmony_ci		 * thus the actual strlen of buf
26862306a36Sopenharmony_ci		 * may be less than len
26962306a36Sopenharmony_ci		 */
27062306a36Sopenharmony_ci		return buf;
27162306a36Sopenharmony_ci	}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	free(buf);
27462306a36Sopenharmony_ci	return NULL;
27562306a36Sopenharmony_ci}
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */
27862306a36Sopenharmony_cistatic int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	unsigned long *set;
28162306a36Sopenharmony_ci	u64 size, *p;
28262306a36Sopenharmony_ci	int i, ret;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	ret = do_read_u64(ff, &size);
28562306a36Sopenharmony_ci	if (ret)
28662306a36Sopenharmony_ci		return ret;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	set = bitmap_zalloc(size);
28962306a36Sopenharmony_ci	if (!set)
29062306a36Sopenharmony_ci		return -ENOMEM;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	p = (u64 *) set;
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	for (i = 0; (u64) i < BITS_TO_U64(size); i++) {
29562306a36Sopenharmony_ci		ret = do_read_u64(ff, p + i);
29662306a36Sopenharmony_ci		if (ret < 0) {
29762306a36Sopenharmony_ci			free(set);
29862306a36Sopenharmony_ci			return ret;
29962306a36Sopenharmony_ci		}
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	*pset  = set;
30362306a36Sopenharmony_ci	*psize = size;
30462306a36Sopenharmony_ci	return 0;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
30862306a36Sopenharmony_cistatic int write_tracing_data(struct feat_fd *ff,
30962306a36Sopenharmony_ci			      struct evlist *evlist)
31062306a36Sopenharmony_ci{
31162306a36Sopenharmony_ci	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
31262306a36Sopenharmony_ci		return -1;
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	return read_tracing_data(ff->fd, &evlist->core.entries);
31562306a36Sopenharmony_ci}
31662306a36Sopenharmony_ci#endif
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic int write_build_id(struct feat_fd *ff,
31962306a36Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
32062306a36Sopenharmony_ci{
32162306a36Sopenharmony_ci	struct perf_session *session;
32262306a36Sopenharmony_ci	int err;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	if (!perf_session__read_build_ids(session, true))
32762306a36Sopenharmony_ci		return -1;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
33062306a36Sopenharmony_ci		return -1;
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	err = perf_session__write_buildid_table(session, ff);
33362306a36Sopenharmony_ci	if (err < 0) {
33462306a36Sopenharmony_ci		pr_debug("failed to write buildid table\n");
33562306a36Sopenharmony_ci		return err;
33662306a36Sopenharmony_ci	}
33762306a36Sopenharmony_ci	perf_session__cache_build_ids(session);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	return 0;
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic int write_hostname(struct feat_fd *ff,
34362306a36Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
34462306a36Sopenharmony_ci{
34562306a36Sopenharmony_ci	struct utsname uts;
34662306a36Sopenharmony_ci	int ret;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	ret = uname(&uts);
34962306a36Sopenharmony_ci	if (ret < 0)
35062306a36Sopenharmony_ci		return -1;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	return do_write_string(ff, uts.nodename);
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int write_osrelease(struct feat_fd *ff,
35662306a36Sopenharmony_ci			   struct evlist *evlist __maybe_unused)
35762306a36Sopenharmony_ci{
35862306a36Sopenharmony_ci	struct utsname uts;
35962306a36Sopenharmony_ci	int ret;
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	ret = uname(&uts);
36262306a36Sopenharmony_ci	if (ret < 0)
36362306a36Sopenharmony_ci		return -1;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return do_write_string(ff, uts.release);
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int write_arch(struct feat_fd *ff,
36962306a36Sopenharmony_ci		      struct evlist *evlist __maybe_unused)
37062306a36Sopenharmony_ci{
37162306a36Sopenharmony_ci	struct utsname uts;
37262306a36Sopenharmony_ci	int ret;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	ret = uname(&uts);
37562306a36Sopenharmony_ci	if (ret < 0)
37662306a36Sopenharmony_ci		return -1;
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	return do_write_string(ff, uts.machine);
37962306a36Sopenharmony_ci}
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_cistatic int write_version(struct feat_fd *ff,
38262306a36Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
38362306a36Sopenharmony_ci{
38462306a36Sopenharmony_ci	return do_write_string(ff, perf_version_string);
38562306a36Sopenharmony_ci}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_cistatic int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	FILE *file;
39062306a36Sopenharmony_ci	char *buf = NULL;
39162306a36Sopenharmony_ci	char *s, *p;
39262306a36Sopenharmony_ci	const char *search = cpuinfo_proc;
39362306a36Sopenharmony_ci	size_t len = 0;
39462306a36Sopenharmony_ci	int ret = -1;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci	if (!search)
39762306a36Sopenharmony_ci		return -1;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	file = fopen("/proc/cpuinfo", "r");
40062306a36Sopenharmony_ci	if (!file)
40162306a36Sopenharmony_ci		return -1;
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	while (getline(&buf, &len, file) > 0) {
40462306a36Sopenharmony_ci		ret = strncmp(buf, search, strlen(search));
40562306a36Sopenharmony_ci		if (!ret)
40662306a36Sopenharmony_ci			break;
40762306a36Sopenharmony_ci	}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	if (ret) {
41062306a36Sopenharmony_ci		ret = -1;
41162306a36Sopenharmony_ci		goto done;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	s = buf;
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	p = strchr(buf, ':');
41762306a36Sopenharmony_ci	if (p && *(p+1) == ' ' && *(p+2))
41862306a36Sopenharmony_ci		s = p + 2;
41962306a36Sopenharmony_ci	p = strchr(s, '\n');
42062306a36Sopenharmony_ci	if (p)
42162306a36Sopenharmony_ci		*p = '\0';
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	/* squash extra space characters (branding string) */
42462306a36Sopenharmony_ci	p = s;
42562306a36Sopenharmony_ci	while (*p) {
42662306a36Sopenharmony_ci		if (isspace(*p)) {
42762306a36Sopenharmony_ci			char *r = p + 1;
42862306a36Sopenharmony_ci			char *q = skip_spaces(r);
42962306a36Sopenharmony_ci			*p = ' ';
43062306a36Sopenharmony_ci			if (q != (p+1))
43162306a36Sopenharmony_ci				while ((*r++ = *q++));
43262306a36Sopenharmony_ci		}
43362306a36Sopenharmony_ci		p++;
43462306a36Sopenharmony_ci	}
43562306a36Sopenharmony_ci	ret = do_write_string(ff, s);
43662306a36Sopenharmony_cidone:
43762306a36Sopenharmony_ci	free(buf);
43862306a36Sopenharmony_ci	fclose(file);
43962306a36Sopenharmony_ci	return ret;
44062306a36Sopenharmony_ci}
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic int write_cpudesc(struct feat_fd *ff,
44362306a36Sopenharmony_ci		       struct evlist *evlist __maybe_unused)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__)
44662306a36Sopenharmony_ci#define CPUINFO_PROC	{ "cpu", }
44762306a36Sopenharmony_ci#elif defined(__s390__)
44862306a36Sopenharmony_ci#define CPUINFO_PROC	{ "vendor_id", }
44962306a36Sopenharmony_ci#elif defined(__sh__)
45062306a36Sopenharmony_ci#define CPUINFO_PROC	{ "cpu type", }
45162306a36Sopenharmony_ci#elif defined(__alpha__) || defined(__mips__)
45262306a36Sopenharmony_ci#define CPUINFO_PROC	{ "cpu model", }
45362306a36Sopenharmony_ci#elif defined(__arm__)
45462306a36Sopenharmony_ci#define CPUINFO_PROC	{ "model name", "Processor", }
45562306a36Sopenharmony_ci#elif defined(__arc__)
45662306a36Sopenharmony_ci#define CPUINFO_PROC	{ "Processor", }
45762306a36Sopenharmony_ci#elif defined(__xtensa__)
45862306a36Sopenharmony_ci#define CPUINFO_PROC	{ "core ID", }
45962306a36Sopenharmony_ci#elif defined(__loongarch__)
46062306a36Sopenharmony_ci#define CPUINFO_PROC	{ "Model Name", }
46162306a36Sopenharmony_ci#else
46262306a36Sopenharmony_ci#define CPUINFO_PROC	{ "model name", }
46362306a36Sopenharmony_ci#endif
46462306a36Sopenharmony_ci	const char *cpuinfo_procs[] = CPUINFO_PROC;
46562306a36Sopenharmony_ci#undef CPUINFO_PROC
46662306a36Sopenharmony_ci	unsigned int i;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) {
46962306a36Sopenharmony_ci		int ret;
47062306a36Sopenharmony_ci		ret = __write_cpudesc(ff, cpuinfo_procs[i]);
47162306a36Sopenharmony_ci		if (ret >= 0)
47262306a36Sopenharmony_ci			return ret;
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci	return -1;
47562306a36Sopenharmony_ci}
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_cistatic int write_nrcpus(struct feat_fd *ff,
47962306a36Sopenharmony_ci			struct evlist *evlist __maybe_unused)
48062306a36Sopenharmony_ci{
48162306a36Sopenharmony_ci	long nr;
48262306a36Sopenharmony_ci	u32 nrc, nra;
48362306a36Sopenharmony_ci	int ret;
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci	nrc = cpu__max_present_cpu().cpu;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	nr = sysconf(_SC_NPROCESSORS_ONLN);
48862306a36Sopenharmony_ci	if (nr < 0)
48962306a36Sopenharmony_ci		return -1;
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	nra = (u32)(nr & UINT_MAX);
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	ret = do_write(ff, &nrc, sizeof(nrc));
49462306a36Sopenharmony_ci	if (ret < 0)
49562306a36Sopenharmony_ci		return ret;
49662306a36Sopenharmony_ci
49762306a36Sopenharmony_ci	return do_write(ff, &nra, sizeof(nra));
49862306a36Sopenharmony_ci}
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_cistatic int write_event_desc(struct feat_fd *ff,
50162306a36Sopenharmony_ci			    struct evlist *evlist)
50262306a36Sopenharmony_ci{
50362306a36Sopenharmony_ci	struct evsel *evsel;
50462306a36Sopenharmony_ci	u32 nre, nri, sz;
50562306a36Sopenharmony_ci	int ret;
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	nre = evlist->core.nr_entries;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci	/*
51062306a36Sopenharmony_ci	 * write number of events
51162306a36Sopenharmony_ci	 */
51262306a36Sopenharmony_ci	ret = do_write(ff, &nre, sizeof(nre));
51362306a36Sopenharmony_ci	if (ret < 0)
51462306a36Sopenharmony_ci		return ret;
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	/*
51762306a36Sopenharmony_ci	 * size of perf_event_attr struct
51862306a36Sopenharmony_ci	 */
51962306a36Sopenharmony_ci	sz = (u32)sizeof(evsel->core.attr);
52062306a36Sopenharmony_ci	ret = do_write(ff, &sz, sizeof(sz));
52162306a36Sopenharmony_ci	if (ret < 0)
52262306a36Sopenharmony_ci		return ret;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
52562306a36Sopenharmony_ci		ret = do_write(ff, &evsel->core.attr, sz);
52662306a36Sopenharmony_ci		if (ret < 0)
52762306a36Sopenharmony_ci			return ret;
52862306a36Sopenharmony_ci		/*
52962306a36Sopenharmony_ci		 * write number of unique id per event
53062306a36Sopenharmony_ci		 * there is one id per instance of an event
53162306a36Sopenharmony_ci		 *
53262306a36Sopenharmony_ci		 * copy into an nri to be independent of the
53362306a36Sopenharmony_ci		 * type of ids,
53462306a36Sopenharmony_ci		 */
53562306a36Sopenharmony_ci		nri = evsel->core.ids;
53662306a36Sopenharmony_ci		ret = do_write(ff, &nri, sizeof(nri));
53762306a36Sopenharmony_ci		if (ret < 0)
53862306a36Sopenharmony_ci			return ret;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci		/*
54162306a36Sopenharmony_ci		 * write event string as passed on cmdline
54262306a36Sopenharmony_ci		 */
54362306a36Sopenharmony_ci		ret = do_write_string(ff, evsel__name(evsel));
54462306a36Sopenharmony_ci		if (ret < 0)
54562306a36Sopenharmony_ci			return ret;
54662306a36Sopenharmony_ci		/*
54762306a36Sopenharmony_ci		 * write unique ids for this event
54862306a36Sopenharmony_ci		 */
54962306a36Sopenharmony_ci		ret = do_write(ff, evsel->core.id, evsel->core.ids * sizeof(u64));
55062306a36Sopenharmony_ci		if (ret < 0)
55162306a36Sopenharmony_ci			return ret;
55262306a36Sopenharmony_ci	}
55362306a36Sopenharmony_ci	return 0;
55462306a36Sopenharmony_ci}
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_cistatic int write_cmdline(struct feat_fd *ff,
55762306a36Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
55862306a36Sopenharmony_ci{
55962306a36Sopenharmony_ci	char pbuf[MAXPATHLEN], *buf;
56062306a36Sopenharmony_ci	int i, ret, n;
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	/* actual path to perf binary */
56362306a36Sopenharmony_ci	buf = perf_exe(pbuf, MAXPATHLEN);
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	/* account for binary path */
56662306a36Sopenharmony_ci	n = perf_env.nr_cmdline + 1;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	ret = do_write(ff, &n, sizeof(n));
56962306a36Sopenharmony_ci	if (ret < 0)
57062306a36Sopenharmony_ci		return ret;
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	ret = do_write_string(ff, buf);
57362306a36Sopenharmony_ci	if (ret < 0)
57462306a36Sopenharmony_ci		return ret;
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	for (i = 0 ; i < perf_env.nr_cmdline; i++) {
57762306a36Sopenharmony_ci		ret = do_write_string(ff, perf_env.cmdline_argv[i]);
57862306a36Sopenharmony_ci		if (ret < 0)
57962306a36Sopenharmony_ci			return ret;
58062306a36Sopenharmony_ci	}
58162306a36Sopenharmony_ci	return 0;
58262306a36Sopenharmony_ci}
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_cistatic int write_cpu_topology(struct feat_fd *ff,
58662306a36Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
58762306a36Sopenharmony_ci{
58862306a36Sopenharmony_ci	struct cpu_topology *tp;
58962306a36Sopenharmony_ci	u32 i;
59062306a36Sopenharmony_ci	int ret, j;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	tp = cpu_topology__new();
59362306a36Sopenharmony_ci	if (!tp)
59462306a36Sopenharmony_ci		return -1;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	ret = do_write(ff, &tp->package_cpus_lists, sizeof(tp->package_cpus_lists));
59762306a36Sopenharmony_ci	if (ret < 0)
59862306a36Sopenharmony_ci		goto done;
59962306a36Sopenharmony_ci
60062306a36Sopenharmony_ci	for (i = 0; i < tp->package_cpus_lists; i++) {
60162306a36Sopenharmony_ci		ret = do_write_string(ff, tp->package_cpus_list[i]);
60262306a36Sopenharmony_ci		if (ret < 0)
60362306a36Sopenharmony_ci			goto done;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci	ret = do_write(ff, &tp->core_cpus_lists, sizeof(tp->core_cpus_lists));
60662306a36Sopenharmony_ci	if (ret < 0)
60762306a36Sopenharmony_ci		goto done;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	for (i = 0; i < tp->core_cpus_lists; i++) {
61062306a36Sopenharmony_ci		ret = do_write_string(ff, tp->core_cpus_list[i]);
61162306a36Sopenharmony_ci		if (ret < 0)
61262306a36Sopenharmony_ci			break;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	ret = perf_env__read_cpu_topology_map(&perf_env);
61662306a36Sopenharmony_ci	if (ret < 0)
61762306a36Sopenharmony_ci		goto done;
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
62062306a36Sopenharmony_ci		ret = do_write(ff, &perf_env.cpu[j].core_id,
62162306a36Sopenharmony_ci			       sizeof(perf_env.cpu[j].core_id));
62262306a36Sopenharmony_ci		if (ret < 0)
62362306a36Sopenharmony_ci			return ret;
62462306a36Sopenharmony_ci		ret = do_write(ff, &perf_env.cpu[j].socket_id,
62562306a36Sopenharmony_ci			       sizeof(perf_env.cpu[j].socket_id));
62662306a36Sopenharmony_ci		if (ret < 0)
62762306a36Sopenharmony_ci			return ret;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	if (!tp->die_cpus_lists)
63162306a36Sopenharmony_ci		goto done;
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	ret = do_write(ff, &tp->die_cpus_lists, sizeof(tp->die_cpus_lists));
63462306a36Sopenharmony_ci	if (ret < 0)
63562306a36Sopenharmony_ci		goto done;
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci	for (i = 0; i < tp->die_cpus_lists; i++) {
63862306a36Sopenharmony_ci		ret = do_write_string(ff, tp->die_cpus_list[i]);
63962306a36Sopenharmony_ci		if (ret < 0)
64062306a36Sopenharmony_ci			goto done;
64162306a36Sopenharmony_ci	}
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	for (j = 0; j < perf_env.nr_cpus_avail; j++) {
64462306a36Sopenharmony_ci		ret = do_write(ff, &perf_env.cpu[j].die_id,
64562306a36Sopenharmony_ci			       sizeof(perf_env.cpu[j].die_id));
64662306a36Sopenharmony_ci		if (ret < 0)
64762306a36Sopenharmony_ci			return ret;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_cidone:
65162306a36Sopenharmony_ci	cpu_topology__delete(tp);
65262306a36Sopenharmony_ci	return ret;
65362306a36Sopenharmony_ci}
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_cistatic int write_total_mem(struct feat_fd *ff,
65862306a36Sopenharmony_ci			   struct evlist *evlist __maybe_unused)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	char *buf = NULL;
66162306a36Sopenharmony_ci	FILE *fp;
66262306a36Sopenharmony_ci	size_t len = 0;
66362306a36Sopenharmony_ci	int ret = -1, n;
66462306a36Sopenharmony_ci	uint64_t mem;
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	fp = fopen("/proc/meminfo", "r");
66762306a36Sopenharmony_ci	if (!fp)
66862306a36Sopenharmony_ci		return -1;
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci	while (getline(&buf, &len, fp) > 0) {
67162306a36Sopenharmony_ci		ret = strncmp(buf, "MemTotal:", 9);
67262306a36Sopenharmony_ci		if (!ret)
67362306a36Sopenharmony_ci			break;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci	if (!ret) {
67662306a36Sopenharmony_ci		n = sscanf(buf, "%*s %"PRIu64, &mem);
67762306a36Sopenharmony_ci		if (n == 1)
67862306a36Sopenharmony_ci			ret = do_write(ff, &mem, sizeof(mem));
67962306a36Sopenharmony_ci	} else
68062306a36Sopenharmony_ci		ret = -1;
68162306a36Sopenharmony_ci	free(buf);
68262306a36Sopenharmony_ci	fclose(fp);
68362306a36Sopenharmony_ci	return ret;
68462306a36Sopenharmony_ci}
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_cistatic int write_numa_topology(struct feat_fd *ff,
68762306a36Sopenharmony_ci			       struct evlist *evlist __maybe_unused)
68862306a36Sopenharmony_ci{
68962306a36Sopenharmony_ci	struct numa_topology *tp;
69062306a36Sopenharmony_ci	int ret = -1;
69162306a36Sopenharmony_ci	u32 i;
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci	tp = numa_topology__new();
69462306a36Sopenharmony_ci	if (!tp)
69562306a36Sopenharmony_ci		return -ENOMEM;
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	ret = do_write(ff, &tp->nr, sizeof(u32));
69862306a36Sopenharmony_ci	if (ret < 0)
69962306a36Sopenharmony_ci		goto err;
70062306a36Sopenharmony_ci
70162306a36Sopenharmony_ci	for (i = 0; i < tp->nr; i++) {
70262306a36Sopenharmony_ci		struct numa_topology_node *n = &tp->nodes[i];
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci		ret = do_write(ff, &n->node, sizeof(u32));
70562306a36Sopenharmony_ci		if (ret < 0)
70662306a36Sopenharmony_ci			goto err;
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_ci		ret = do_write(ff, &n->mem_total, sizeof(u64));
70962306a36Sopenharmony_ci		if (ret)
71062306a36Sopenharmony_ci			goto err;
71162306a36Sopenharmony_ci
71262306a36Sopenharmony_ci		ret = do_write(ff, &n->mem_free, sizeof(u64));
71362306a36Sopenharmony_ci		if (ret)
71462306a36Sopenharmony_ci			goto err;
71562306a36Sopenharmony_ci
71662306a36Sopenharmony_ci		ret = do_write_string(ff, n->cpus);
71762306a36Sopenharmony_ci		if (ret < 0)
71862306a36Sopenharmony_ci			goto err;
71962306a36Sopenharmony_ci	}
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	ret = 0;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_cierr:
72462306a36Sopenharmony_ci	numa_topology__delete(tp);
72562306a36Sopenharmony_ci	return ret;
72662306a36Sopenharmony_ci}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci/*
72962306a36Sopenharmony_ci * File format:
73062306a36Sopenharmony_ci *
73162306a36Sopenharmony_ci * struct pmu_mappings {
73262306a36Sopenharmony_ci *	u32	pmu_num;
73362306a36Sopenharmony_ci *	struct pmu_map {
73462306a36Sopenharmony_ci *		u32	type;
73562306a36Sopenharmony_ci *		char	name[];
73662306a36Sopenharmony_ci *	}[pmu_num];
73762306a36Sopenharmony_ci * };
73862306a36Sopenharmony_ci */
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_cistatic int write_pmu_mappings(struct feat_fd *ff,
74162306a36Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
74262306a36Sopenharmony_ci{
74362306a36Sopenharmony_ci	struct perf_pmu *pmu = NULL;
74462306a36Sopenharmony_ci	u32 pmu_num = 0;
74562306a36Sopenharmony_ci	int ret;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	/*
74862306a36Sopenharmony_ci	 * Do a first pass to count number of pmu to avoid lseek so this
74962306a36Sopenharmony_ci	 * works in pipe mode as well.
75062306a36Sopenharmony_ci	 */
75162306a36Sopenharmony_ci	while ((pmu = perf_pmus__scan(pmu)))
75262306a36Sopenharmony_ci		pmu_num++;
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci	ret = do_write(ff, &pmu_num, sizeof(pmu_num));
75562306a36Sopenharmony_ci	if (ret < 0)
75662306a36Sopenharmony_ci		return ret;
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci	while ((pmu = perf_pmus__scan(pmu))) {
75962306a36Sopenharmony_ci		ret = do_write(ff, &pmu->type, sizeof(pmu->type));
76062306a36Sopenharmony_ci		if (ret < 0)
76162306a36Sopenharmony_ci			return ret;
76262306a36Sopenharmony_ci
76362306a36Sopenharmony_ci		ret = do_write_string(ff, pmu->name);
76462306a36Sopenharmony_ci		if (ret < 0)
76562306a36Sopenharmony_ci			return ret;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci
76862306a36Sopenharmony_ci	return 0;
76962306a36Sopenharmony_ci}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci/*
77262306a36Sopenharmony_ci * File format:
77362306a36Sopenharmony_ci *
77462306a36Sopenharmony_ci * struct group_descs {
77562306a36Sopenharmony_ci *	u32	nr_groups;
77662306a36Sopenharmony_ci *	struct group_desc {
77762306a36Sopenharmony_ci *		char	name[];
77862306a36Sopenharmony_ci *		u32	leader_idx;
77962306a36Sopenharmony_ci *		u32	nr_members;
78062306a36Sopenharmony_ci *	}[nr_groups];
78162306a36Sopenharmony_ci * };
78262306a36Sopenharmony_ci */
78362306a36Sopenharmony_cistatic int write_group_desc(struct feat_fd *ff,
78462306a36Sopenharmony_ci			    struct evlist *evlist)
78562306a36Sopenharmony_ci{
78662306a36Sopenharmony_ci	u32 nr_groups = evlist__nr_groups(evlist);
78762306a36Sopenharmony_ci	struct evsel *evsel;
78862306a36Sopenharmony_ci	int ret;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	ret = do_write(ff, &nr_groups, sizeof(nr_groups));
79162306a36Sopenharmony_ci	if (ret < 0)
79262306a36Sopenharmony_ci		return ret;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
79562306a36Sopenharmony_ci		if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) {
79662306a36Sopenharmony_ci			const char *name = evsel->group_name ?: "{anon_group}";
79762306a36Sopenharmony_ci			u32 leader_idx = evsel->core.idx;
79862306a36Sopenharmony_ci			u32 nr_members = evsel->core.nr_members;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci			ret = do_write_string(ff, name);
80162306a36Sopenharmony_ci			if (ret < 0)
80262306a36Sopenharmony_ci				return ret;
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci			ret = do_write(ff, &leader_idx, sizeof(leader_idx));
80562306a36Sopenharmony_ci			if (ret < 0)
80662306a36Sopenharmony_ci				return ret;
80762306a36Sopenharmony_ci
80862306a36Sopenharmony_ci			ret = do_write(ff, &nr_members, sizeof(nr_members));
80962306a36Sopenharmony_ci			if (ret < 0)
81062306a36Sopenharmony_ci				return ret;
81162306a36Sopenharmony_ci		}
81262306a36Sopenharmony_ci	}
81362306a36Sopenharmony_ci	return 0;
81462306a36Sopenharmony_ci}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci/*
81762306a36Sopenharmony_ci * Return the CPU id as a raw string.
81862306a36Sopenharmony_ci *
81962306a36Sopenharmony_ci * Each architecture should provide a more precise id string that
82062306a36Sopenharmony_ci * can be use to match the architecture's "mapfile".
82162306a36Sopenharmony_ci */
82262306a36Sopenharmony_cichar * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused)
82362306a36Sopenharmony_ci{
82462306a36Sopenharmony_ci	return NULL;
82562306a36Sopenharmony_ci}
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci/* Return zero when the cpuid from the mapfile.csv matches the
82862306a36Sopenharmony_ci * cpuid string generated on this platform.
82962306a36Sopenharmony_ci * Otherwise return non-zero.
83062306a36Sopenharmony_ci */
83162306a36Sopenharmony_ciint __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	regex_t re;
83462306a36Sopenharmony_ci	regmatch_t pmatch[1];
83562306a36Sopenharmony_ci	int match;
83662306a36Sopenharmony_ci
83762306a36Sopenharmony_ci	if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) {
83862306a36Sopenharmony_ci		/* Warn unable to generate match particular string. */
83962306a36Sopenharmony_ci		pr_info("Invalid regular expression %s\n", mapcpuid);
84062306a36Sopenharmony_ci		return 1;
84162306a36Sopenharmony_ci	}
84262306a36Sopenharmony_ci
84362306a36Sopenharmony_ci	match = !regexec(&re, cpuid, 1, pmatch, 0);
84462306a36Sopenharmony_ci	regfree(&re);
84562306a36Sopenharmony_ci	if (match) {
84662306a36Sopenharmony_ci		size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so);
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci		/* Verify the entire string matched. */
84962306a36Sopenharmony_ci		if (match_len == strlen(cpuid))
85062306a36Sopenharmony_ci			return 0;
85162306a36Sopenharmony_ci	}
85262306a36Sopenharmony_ci	return 1;
85362306a36Sopenharmony_ci}
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci/*
85662306a36Sopenharmony_ci * default get_cpuid(): nothing gets recorded
85762306a36Sopenharmony_ci * actual implementation must be in arch/$(SRCARCH)/util/header.c
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_ciint __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused)
86062306a36Sopenharmony_ci{
86162306a36Sopenharmony_ci	return ENOSYS; /* Not implemented */
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic int write_cpuid(struct feat_fd *ff,
86562306a36Sopenharmony_ci		       struct evlist *evlist __maybe_unused)
86662306a36Sopenharmony_ci{
86762306a36Sopenharmony_ci	char buffer[64];
86862306a36Sopenharmony_ci	int ret;
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_ci	ret = get_cpuid(buffer, sizeof(buffer));
87162306a36Sopenharmony_ci	if (ret)
87262306a36Sopenharmony_ci		return -1;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci	return do_write_string(ff, buffer);
87562306a36Sopenharmony_ci}
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_cistatic int write_branch_stack(struct feat_fd *ff __maybe_unused,
87862306a36Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	return 0;
88162306a36Sopenharmony_ci}
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_cistatic int write_auxtrace(struct feat_fd *ff,
88462306a36Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
88562306a36Sopenharmony_ci{
88662306a36Sopenharmony_ci	struct perf_session *session;
88762306a36Sopenharmony_ci	int err;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
89062306a36Sopenharmony_ci		return -1;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	err = auxtrace_index__write(ff->fd, &session->auxtrace_index);
89562306a36Sopenharmony_ci	if (err < 0)
89662306a36Sopenharmony_ci		pr_err("Failed to write auxtrace index\n");
89762306a36Sopenharmony_ci	return err;
89862306a36Sopenharmony_ci}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_cistatic int write_clockid(struct feat_fd *ff,
90162306a36Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
90262306a36Sopenharmony_ci{
90362306a36Sopenharmony_ci	return do_write(ff, &ff->ph->env.clock.clockid_res_ns,
90462306a36Sopenharmony_ci			sizeof(ff->ph->env.clock.clockid_res_ns));
90562306a36Sopenharmony_ci}
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_cistatic int write_clock_data(struct feat_fd *ff,
90862306a36Sopenharmony_ci			    struct evlist *evlist __maybe_unused)
90962306a36Sopenharmony_ci{
91062306a36Sopenharmony_ci	u64 *data64;
91162306a36Sopenharmony_ci	u32 data32;
91262306a36Sopenharmony_ci	int ret;
91362306a36Sopenharmony_ci
91462306a36Sopenharmony_ci	/* version */
91562306a36Sopenharmony_ci	data32 = 1;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	ret = do_write(ff, &data32, sizeof(data32));
91862306a36Sopenharmony_ci	if (ret < 0)
91962306a36Sopenharmony_ci		return ret;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci	/* clockid */
92262306a36Sopenharmony_ci	data32 = ff->ph->env.clock.clockid;
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_ci	ret = do_write(ff, &data32, sizeof(data32));
92562306a36Sopenharmony_ci	if (ret < 0)
92662306a36Sopenharmony_ci		return ret;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	/* TOD ref time */
92962306a36Sopenharmony_ci	data64 = &ff->ph->env.clock.tod_ns;
93062306a36Sopenharmony_ci
93162306a36Sopenharmony_ci	ret = do_write(ff, data64, sizeof(*data64));
93262306a36Sopenharmony_ci	if (ret < 0)
93362306a36Sopenharmony_ci		return ret;
93462306a36Sopenharmony_ci
93562306a36Sopenharmony_ci	/* clockid ref time */
93662306a36Sopenharmony_ci	data64 = &ff->ph->env.clock.clockid_ns;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	return do_write(ff, data64, sizeof(*data64));
93962306a36Sopenharmony_ci}
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_cistatic int write_hybrid_topology(struct feat_fd *ff,
94262306a36Sopenharmony_ci				 struct evlist *evlist __maybe_unused)
94362306a36Sopenharmony_ci{
94462306a36Sopenharmony_ci	struct hybrid_topology *tp;
94562306a36Sopenharmony_ci	int ret;
94662306a36Sopenharmony_ci	u32 i;
94762306a36Sopenharmony_ci
94862306a36Sopenharmony_ci	tp = hybrid_topology__new();
94962306a36Sopenharmony_ci	if (!tp)
95062306a36Sopenharmony_ci		return -ENOENT;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	ret = do_write(ff, &tp->nr, sizeof(u32));
95362306a36Sopenharmony_ci	if (ret < 0)
95462306a36Sopenharmony_ci		goto err;
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	for (i = 0; i < tp->nr; i++) {
95762306a36Sopenharmony_ci		struct hybrid_topology_node *n = &tp->nodes[i];
95862306a36Sopenharmony_ci
95962306a36Sopenharmony_ci		ret = do_write_string(ff, n->pmu_name);
96062306a36Sopenharmony_ci		if (ret < 0)
96162306a36Sopenharmony_ci			goto err;
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci		ret = do_write_string(ff, n->cpus);
96462306a36Sopenharmony_ci		if (ret < 0)
96562306a36Sopenharmony_ci			goto err;
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	ret = 0;
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_cierr:
97162306a36Sopenharmony_ci	hybrid_topology__delete(tp);
97262306a36Sopenharmony_ci	return ret;
97362306a36Sopenharmony_ci}
97462306a36Sopenharmony_ci
97562306a36Sopenharmony_cistatic int write_dir_format(struct feat_fd *ff,
97662306a36Sopenharmony_ci			    struct evlist *evlist __maybe_unused)
97762306a36Sopenharmony_ci{
97862306a36Sopenharmony_ci	struct perf_session *session;
97962306a36Sopenharmony_ci	struct perf_data *data;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
98262306a36Sopenharmony_ci	data = session->data;
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	if (WARN_ON(!perf_data__is_dir(data)))
98562306a36Sopenharmony_ci		return -1;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	return do_write(ff, &data->dir.version, sizeof(data->dir.version));
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_ci/*
99162306a36Sopenharmony_ci * Check whether a CPU is online
99262306a36Sopenharmony_ci *
99362306a36Sopenharmony_ci * Returns:
99462306a36Sopenharmony_ci *     1 -> if CPU is online
99562306a36Sopenharmony_ci *     0 -> if CPU is offline
99662306a36Sopenharmony_ci *    -1 -> error case
99762306a36Sopenharmony_ci */
99862306a36Sopenharmony_ciint is_cpu_online(unsigned int cpu)
99962306a36Sopenharmony_ci{
100062306a36Sopenharmony_ci	char *str;
100162306a36Sopenharmony_ci	size_t strlen;
100262306a36Sopenharmony_ci	char buf[256];
100362306a36Sopenharmony_ci	int status = -1;
100462306a36Sopenharmony_ci	struct stat statbuf;
100562306a36Sopenharmony_ci
100662306a36Sopenharmony_ci	snprintf(buf, sizeof(buf),
100762306a36Sopenharmony_ci		"/sys/devices/system/cpu/cpu%d", cpu);
100862306a36Sopenharmony_ci	if (stat(buf, &statbuf) != 0)
100962306a36Sopenharmony_ci		return 0;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	/*
101262306a36Sopenharmony_ci	 * Check if /sys/devices/system/cpu/cpux/online file
101362306a36Sopenharmony_ci	 * exists. Some cases cpu0 won't have online file since
101462306a36Sopenharmony_ci	 * it is not expected to be turned off generally.
101562306a36Sopenharmony_ci	 * In kernels without CONFIG_HOTPLUG_CPU, this
101662306a36Sopenharmony_ci	 * file won't exist
101762306a36Sopenharmony_ci	 */
101862306a36Sopenharmony_ci	snprintf(buf, sizeof(buf),
101962306a36Sopenharmony_ci		"/sys/devices/system/cpu/cpu%d/online", cpu);
102062306a36Sopenharmony_ci	if (stat(buf, &statbuf) != 0)
102162306a36Sopenharmony_ci		return 1;
102262306a36Sopenharmony_ci
102362306a36Sopenharmony_ci	/*
102462306a36Sopenharmony_ci	 * Read online file using sysfs__read_str.
102562306a36Sopenharmony_ci	 * If read or open fails, return -1.
102662306a36Sopenharmony_ci	 * If read succeeds, return value from file
102762306a36Sopenharmony_ci	 * which gets stored in "str"
102862306a36Sopenharmony_ci	 */
102962306a36Sopenharmony_ci	snprintf(buf, sizeof(buf),
103062306a36Sopenharmony_ci		"devices/system/cpu/cpu%d/online", cpu);
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci	if (sysfs__read_str(buf, &str, &strlen) < 0)
103362306a36Sopenharmony_ci		return status;
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	status = atoi(str);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	free(str);
103862306a36Sopenharmony_ci	return status;
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
104262306a36Sopenharmony_cistatic int write_bpf_prog_info(struct feat_fd *ff,
104362306a36Sopenharmony_ci			       struct evlist *evlist __maybe_unused)
104462306a36Sopenharmony_ci{
104562306a36Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
104662306a36Sopenharmony_ci	struct rb_root *root;
104762306a36Sopenharmony_ci	struct rb_node *next;
104862306a36Sopenharmony_ci	int ret;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	down_read(&env->bpf_progs.lock);
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	ret = do_write(ff, &env->bpf_progs.infos_cnt,
105362306a36Sopenharmony_ci		       sizeof(env->bpf_progs.infos_cnt));
105462306a36Sopenharmony_ci	if (ret < 0)
105562306a36Sopenharmony_ci		goto out;
105662306a36Sopenharmony_ci
105762306a36Sopenharmony_ci	root = &env->bpf_progs.infos;
105862306a36Sopenharmony_ci	next = rb_first(root);
105962306a36Sopenharmony_ci	while (next) {
106062306a36Sopenharmony_ci		struct bpf_prog_info_node *node;
106162306a36Sopenharmony_ci		size_t len;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
106462306a36Sopenharmony_ci		next = rb_next(&node->rb_node);
106562306a36Sopenharmony_ci		len = sizeof(struct perf_bpil) +
106662306a36Sopenharmony_ci			node->info_linear->data_len;
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci		/* before writing to file, translate address to offset */
106962306a36Sopenharmony_ci		bpil_addr_to_offs(node->info_linear);
107062306a36Sopenharmony_ci		ret = do_write(ff, node->info_linear, len);
107162306a36Sopenharmony_ci		/*
107262306a36Sopenharmony_ci		 * translate back to address even when do_write() fails,
107362306a36Sopenharmony_ci		 * so that this function never changes the data.
107462306a36Sopenharmony_ci		 */
107562306a36Sopenharmony_ci		bpil_offs_to_addr(node->info_linear);
107662306a36Sopenharmony_ci		if (ret < 0)
107762306a36Sopenharmony_ci			goto out;
107862306a36Sopenharmony_ci	}
107962306a36Sopenharmony_ciout:
108062306a36Sopenharmony_ci	up_read(&env->bpf_progs.lock);
108162306a36Sopenharmony_ci	return ret;
108262306a36Sopenharmony_ci}
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cistatic int write_bpf_btf(struct feat_fd *ff,
108562306a36Sopenharmony_ci			 struct evlist *evlist __maybe_unused)
108662306a36Sopenharmony_ci{
108762306a36Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
108862306a36Sopenharmony_ci	struct rb_root *root;
108962306a36Sopenharmony_ci	struct rb_node *next;
109062306a36Sopenharmony_ci	int ret;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	down_read(&env->bpf_progs.lock);
109362306a36Sopenharmony_ci
109462306a36Sopenharmony_ci	ret = do_write(ff, &env->bpf_progs.btfs_cnt,
109562306a36Sopenharmony_ci		       sizeof(env->bpf_progs.btfs_cnt));
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (ret < 0)
109862306a36Sopenharmony_ci		goto out;
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ci	root = &env->bpf_progs.btfs;
110162306a36Sopenharmony_ci	next = rb_first(root);
110262306a36Sopenharmony_ci	while (next) {
110362306a36Sopenharmony_ci		struct btf_node *node;
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci		node = rb_entry(next, struct btf_node, rb_node);
110662306a36Sopenharmony_ci		next = rb_next(&node->rb_node);
110762306a36Sopenharmony_ci		ret = do_write(ff, &node->id,
110862306a36Sopenharmony_ci			       sizeof(u32) * 2 + node->data_size);
110962306a36Sopenharmony_ci		if (ret < 0)
111062306a36Sopenharmony_ci			goto out;
111162306a36Sopenharmony_ci	}
111262306a36Sopenharmony_ciout:
111362306a36Sopenharmony_ci	up_read(&env->bpf_progs.lock);
111462306a36Sopenharmony_ci	return ret;
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_cistatic int cpu_cache_level__sort(const void *a, const void *b)
111962306a36Sopenharmony_ci{
112062306a36Sopenharmony_ci	struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
112162306a36Sopenharmony_ci	struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b;
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci	return cache_a->level - cache_b->level;
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	if (a->level != b->level)
112962306a36Sopenharmony_ci		return false;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	if (a->line_size != b->line_size)
113262306a36Sopenharmony_ci		return false;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	if (a->sets != b->sets)
113562306a36Sopenharmony_ci		return false;
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_ci	if (a->ways != b->ways)
113862306a36Sopenharmony_ci		return false;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	if (strcmp(a->type, b->type))
114162306a36Sopenharmony_ci		return false;
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci	if (strcmp(a->size, b->size))
114462306a36Sopenharmony_ci		return false;
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	if (strcmp(a->map, b->map))
114762306a36Sopenharmony_ci		return false;
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	return true;
115062306a36Sopenharmony_ci}
115162306a36Sopenharmony_ci
115262306a36Sopenharmony_cistatic int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level)
115362306a36Sopenharmony_ci{
115462306a36Sopenharmony_ci	char path[PATH_MAX], file[PATH_MAX];
115562306a36Sopenharmony_ci	struct stat st;
115662306a36Sopenharmony_ci	size_t len;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
115962306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (stat(file, &st))
116262306a36Sopenharmony_ci		return 1;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/level", path);
116562306a36Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->level))
116662306a36Sopenharmony_ci		return -1;
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
116962306a36Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->line_size))
117062306a36Sopenharmony_ci		return -1;
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
117362306a36Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->sets))
117462306a36Sopenharmony_ci		return -1;
117562306a36Sopenharmony_ci
117662306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
117762306a36Sopenharmony_ci	if (sysfs__read_int(file, (int *) &cache->ways))
117862306a36Sopenharmony_ci		return -1;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/type", path);
118162306a36Sopenharmony_ci	if (sysfs__read_str(file, &cache->type, &len))
118262306a36Sopenharmony_ci		return -1;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	cache->type[len] = 0;
118562306a36Sopenharmony_ci	cache->type = strim(cache->type);
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/size", path);
118862306a36Sopenharmony_ci	if (sysfs__read_str(file, &cache->size, &len)) {
118962306a36Sopenharmony_ci		zfree(&cache->type);
119062306a36Sopenharmony_ci		return -1;
119162306a36Sopenharmony_ci	}
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	cache->size[len] = 0;
119462306a36Sopenharmony_ci	cache->size = strim(cache->size);
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci	scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
119762306a36Sopenharmony_ci	if (sysfs__read_str(file, &cache->map, &len)) {
119862306a36Sopenharmony_ci		zfree(&cache->size);
119962306a36Sopenharmony_ci		zfree(&cache->type);
120062306a36Sopenharmony_ci		return -1;
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_ci	cache->map[len] = 0;
120462306a36Sopenharmony_ci	cache->map = strim(cache->map);
120562306a36Sopenharmony_ci	return 0;
120662306a36Sopenharmony_ci}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_cistatic void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c)
120962306a36Sopenharmony_ci{
121062306a36Sopenharmony_ci	fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci/*
121462306a36Sopenharmony_ci * Build caches levels for a particular CPU from the data in
121562306a36Sopenharmony_ci * /sys/devices/system/cpu/cpu<cpu>/cache/
121662306a36Sopenharmony_ci * The cache level data is stored in caches[] from index at
121762306a36Sopenharmony_ci * *cntp.
121862306a36Sopenharmony_ci */
121962306a36Sopenharmony_ciint build_caches_for_cpu(u32 cpu, struct cpu_cache_level caches[], u32 *cntp)
122062306a36Sopenharmony_ci{
122162306a36Sopenharmony_ci	u16 level;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	for (level = 0; level < MAX_CACHE_LVL; level++) {
122462306a36Sopenharmony_ci		struct cpu_cache_level c;
122562306a36Sopenharmony_ci		int err;
122662306a36Sopenharmony_ci		u32 i;
122762306a36Sopenharmony_ci
122862306a36Sopenharmony_ci		err = cpu_cache_level__read(&c, cpu, level);
122962306a36Sopenharmony_ci		if (err < 0)
123062306a36Sopenharmony_ci			return err;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci		if (err == 1)
123362306a36Sopenharmony_ci			break;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		for (i = 0; i < *cntp; i++) {
123662306a36Sopenharmony_ci			if (cpu_cache_level__cmp(&c, &caches[i]))
123762306a36Sopenharmony_ci				break;
123862306a36Sopenharmony_ci		}
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci		if (i == *cntp) {
124162306a36Sopenharmony_ci			caches[*cntp] = c;
124262306a36Sopenharmony_ci			*cntp = *cntp + 1;
124362306a36Sopenharmony_ci		} else
124462306a36Sopenharmony_ci			cpu_cache_level__free(&c);
124562306a36Sopenharmony_ci	}
124662306a36Sopenharmony_ci
124762306a36Sopenharmony_ci	return 0;
124862306a36Sopenharmony_ci}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_cistatic int build_caches(struct cpu_cache_level caches[], u32 *cntp)
125162306a36Sopenharmony_ci{
125262306a36Sopenharmony_ci	u32 nr, cpu, cnt = 0;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	nr = cpu__max_cpu().cpu;
125562306a36Sopenharmony_ci
125662306a36Sopenharmony_ci	for (cpu = 0; cpu < nr; cpu++) {
125762306a36Sopenharmony_ci		int ret = build_caches_for_cpu(cpu, caches, &cnt);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci		if (ret)
126062306a36Sopenharmony_ci			return ret;
126162306a36Sopenharmony_ci	}
126262306a36Sopenharmony_ci	*cntp = cnt;
126362306a36Sopenharmony_ci	return 0;
126462306a36Sopenharmony_ci}
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_cistatic int write_cache(struct feat_fd *ff,
126762306a36Sopenharmony_ci		       struct evlist *evlist __maybe_unused)
126862306a36Sopenharmony_ci{
126962306a36Sopenharmony_ci	u32 max_caches = cpu__max_cpu().cpu * MAX_CACHE_LVL;
127062306a36Sopenharmony_ci	struct cpu_cache_level caches[max_caches];
127162306a36Sopenharmony_ci	u32 cnt = 0, i, version = 1;
127262306a36Sopenharmony_ci	int ret;
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_ci	ret = build_caches(caches, &cnt);
127562306a36Sopenharmony_ci	if (ret)
127662306a36Sopenharmony_ci		goto out;
127762306a36Sopenharmony_ci
127862306a36Sopenharmony_ci	qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	ret = do_write(ff, &version, sizeof(u32));
128162306a36Sopenharmony_ci	if (ret < 0)
128262306a36Sopenharmony_ci		goto out;
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_ci	ret = do_write(ff, &cnt, sizeof(u32));
128562306a36Sopenharmony_ci	if (ret < 0)
128662306a36Sopenharmony_ci		goto out;
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	for (i = 0; i < cnt; i++) {
128962306a36Sopenharmony_ci		struct cpu_cache_level *c = &caches[i];
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci		#define _W(v)					\
129262306a36Sopenharmony_ci			ret = do_write(ff, &c->v, sizeof(u32));	\
129362306a36Sopenharmony_ci			if (ret < 0)				\
129462306a36Sopenharmony_ci				goto out;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci		_W(level)
129762306a36Sopenharmony_ci		_W(line_size)
129862306a36Sopenharmony_ci		_W(sets)
129962306a36Sopenharmony_ci		_W(ways)
130062306a36Sopenharmony_ci		#undef _W
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		#define _W(v)						\
130362306a36Sopenharmony_ci			ret = do_write_string(ff, (const char *) c->v);	\
130462306a36Sopenharmony_ci			if (ret < 0)					\
130562306a36Sopenharmony_ci				goto out;
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci		_W(type)
130862306a36Sopenharmony_ci		_W(size)
130962306a36Sopenharmony_ci		_W(map)
131062306a36Sopenharmony_ci		#undef _W
131162306a36Sopenharmony_ci	}
131262306a36Sopenharmony_ci
131362306a36Sopenharmony_ciout:
131462306a36Sopenharmony_ci	for (i = 0; i < cnt; i++)
131562306a36Sopenharmony_ci		cpu_cache_level__free(&caches[i]);
131662306a36Sopenharmony_ci	return ret;
131762306a36Sopenharmony_ci}
131862306a36Sopenharmony_ci
131962306a36Sopenharmony_cistatic int write_stat(struct feat_fd *ff __maybe_unused,
132062306a36Sopenharmony_ci		      struct evlist *evlist __maybe_unused)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	return 0;
132362306a36Sopenharmony_ci}
132462306a36Sopenharmony_ci
132562306a36Sopenharmony_cistatic int write_sample_time(struct feat_fd *ff,
132662306a36Sopenharmony_ci			     struct evlist *evlist)
132762306a36Sopenharmony_ci{
132862306a36Sopenharmony_ci	int ret;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	ret = do_write(ff, &evlist->first_sample_time,
133162306a36Sopenharmony_ci		       sizeof(evlist->first_sample_time));
133262306a36Sopenharmony_ci	if (ret < 0)
133362306a36Sopenharmony_ci		return ret;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	return do_write(ff, &evlist->last_sample_time,
133662306a36Sopenharmony_ci			sizeof(evlist->last_sample_time));
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci
134062306a36Sopenharmony_cistatic int memory_node__read(struct memory_node *n, unsigned long idx)
134162306a36Sopenharmony_ci{
134262306a36Sopenharmony_ci	unsigned int phys, size = 0;
134362306a36Sopenharmony_ci	char path[PATH_MAX];
134462306a36Sopenharmony_ci	struct dirent *ent;
134562306a36Sopenharmony_ci	DIR *dir;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci#define for_each_memory(mem, dir)					\
134862306a36Sopenharmony_ci	while ((ent = readdir(dir)))					\
134962306a36Sopenharmony_ci		if (strcmp(ent->d_name, ".") &&				\
135062306a36Sopenharmony_ci		    strcmp(ent->d_name, "..") &&			\
135162306a36Sopenharmony_ci		    sscanf(ent->d_name, "memory%u", &mem) == 1)
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci	scnprintf(path, PATH_MAX,
135462306a36Sopenharmony_ci		  "%s/devices/system/node/node%lu",
135562306a36Sopenharmony_ci		  sysfs__mountpoint(), idx);
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	dir = opendir(path);
135862306a36Sopenharmony_ci	if (!dir) {
135962306a36Sopenharmony_ci		pr_warning("failed: can't open memory sysfs data\n");
136062306a36Sopenharmony_ci		return -1;
136162306a36Sopenharmony_ci	}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	for_each_memory(phys, dir) {
136462306a36Sopenharmony_ci		size = max(phys, size);
136562306a36Sopenharmony_ci	}
136662306a36Sopenharmony_ci
136762306a36Sopenharmony_ci	size++;
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	n->set = bitmap_zalloc(size);
137062306a36Sopenharmony_ci	if (!n->set) {
137162306a36Sopenharmony_ci		closedir(dir);
137262306a36Sopenharmony_ci		return -ENOMEM;
137362306a36Sopenharmony_ci	}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci	n->node = idx;
137662306a36Sopenharmony_ci	n->size = size;
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ci	rewinddir(dir);
137962306a36Sopenharmony_ci
138062306a36Sopenharmony_ci	for_each_memory(phys, dir) {
138162306a36Sopenharmony_ci		__set_bit(phys, n->set);
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	closedir(dir);
138562306a36Sopenharmony_ci	return 0;
138662306a36Sopenharmony_ci}
138762306a36Sopenharmony_ci
138862306a36Sopenharmony_cistatic void memory_node__delete_nodes(struct memory_node *nodesp, u64 cnt)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	for (u64 i = 0; i < cnt; i++)
139162306a36Sopenharmony_ci		bitmap_free(nodesp[i].set);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci	free(nodesp);
139462306a36Sopenharmony_ci}
139562306a36Sopenharmony_ci
139662306a36Sopenharmony_cistatic int memory_node__sort(const void *a, const void *b)
139762306a36Sopenharmony_ci{
139862306a36Sopenharmony_ci	const struct memory_node *na = a;
139962306a36Sopenharmony_ci	const struct memory_node *nb = b;
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	return na->node - nb->node;
140262306a36Sopenharmony_ci}
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_cistatic int build_mem_topology(struct memory_node **nodesp, u64 *cntp)
140562306a36Sopenharmony_ci{
140662306a36Sopenharmony_ci	char path[PATH_MAX];
140762306a36Sopenharmony_ci	struct dirent *ent;
140862306a36Sopenharmony_ci	DIR *dir;
140962306a36Sopenharmony_ci	int ret = 0;
141062306a36Sopenharmony_ci	size_t cnt = 0, size = 0;
141162306a36Sopenharmony_ci	struct memory_node *nodes = NULL;
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_ci	scnprintf(path, PATH_MAX, "%s/devices/system/node/",
141462306a36Sopenharmony_ci		  sysfs__mountpoint());
141562306a36Sopenharmony_ci
141662306a36Sopenharmony_ci	dir = opendir(path);
141762306a36Sopenharmony_ci	if (!dir) {
141862306a36Sopenharmony_ci		pr_debug2("%s: couldn't read %s, does this arch have topology information?\n",
141962306a36Sopenharmony_ci			  __func__, path);
142062306a36Sopenharmony_ci		return -1;
142162306a36Sopenharmony_ci	}
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ci	while (!ret && (ent = readdir(dir))) {
142462306a36Sopenharmony_ci		unsigned int idx;
142562306a36Sopenharmony_ci		int r;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci		if (!strcmp(ent->d_name, ".") ||
142862306a36Sopenharmony_ci		    !strcmp(ent->d_name, ".."))
142962306a36Sopenharmony_ci			continue;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci		r = sscanf(ent->d_name, "node%u", &idx);
143262306a36Sopenharmony_ci		if (r != 1)
143362306a36Sopenharmony_ci			continue;
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci		if (cnt >= size) {
143662306a36Sopenharmony_ci			struct memory_node *new_nodes =
143762306a36Sopenharmony_ci				reallocarray(nodes, cnt + 4, sizeof(*nodes));
143862306a36Sopenharmony_ci
143962306a36Sopenharmony_ci			if (!new_nodes) {
144062306a36Sopenharmony_ci				pr_err("Failed to write MEM_TOPOLOGY, size %zd nodes\n", size);
144162306a36Sopenharmony_ci				ret = -ENOMEM;
144262306a36Sopenharmony_ci				goto out;
144362306a36Sopenharmony_ci			}
144462306a36Sopenharmony_ci			nodes = new_nodes;
144562306a36Sopenharmony_ci			size += 4;
144662306a36Sopenharmony_ci		}
144762306a36Sopenharmony_ci		ret = memory_node__read(&nodes[cnt], idx);
144862306a36Sopenharmony_ci		if (!ret)
144962306a36Sopenharmony_ci			cnt += 1;
145062306a36Sopenharmony_ci	}
145162306a36Sopenharmony_ciout:
145262306a36Sopenharmony_ci	closedir(dir);
145362306a36Sopenharmony_ci	if (!ret) {
145462306a36Sopenharmony_ci		*cntp = cnt;
145562306a36Sopenharmony_ci		*nodesp = nodes;
145662306a36Sopenharmony_ci		qsort(nodes, cnt, sizeof(nodes[0]), memory_node__sort);
145762306a36Sopenharmony_ci	} else
145862306a36Sopenharmony_ci		memory_node__delete_nodes(nodes, cnt);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	return ret;
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci/*
146462306a36Sopenharmony_ci * The MEM_TOPOLOGY holds physical memory map for every
146562306a36Sopenharmony_ci * node in system. The format of data is as follows:
146662306a36Sopenharmony_ci *
146762306a36Sopenharmony_ci *  0 - version          | for future changes
146862306a36Sopenharmony_ci *  8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes
146962306a36Sopenharmony_ci * 16 - count            | number of nodes
147062306a36Sopenharmony_ci *
147162306a36Sopenharmony_ci * For each node we store map of physical indexes for
147262306a36Sopenharmony_ci * each node:
147362306a36Sopenharmony_ci *
147462306a36Sopenharmony_ci * 32 - node id          | node index
147562306a36Sopenharmony_ci * 40 - size             | size of bitmap
147662306a36Sopenharmony_ci * 48 - bitmap           | bitmap of memory indexes that belongs to node
147762306a36Sopenharmony_ci */
147862306a36Sopenharmony_cistatic int write_mem_topology(struct feat_fd *ff __maybe_unused,
147962306a36Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
148062306a36Sopenharmony_ci{
148162306a36Sopenharmony_ci	struct memory_node *nodes = NULL;
148262306a36Sopenharmony_ci	u64 bsize, version = 1, i, nr = 0;
148362306a36Sopenharmony_ci	int ret;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	ret = sysfs__read_xll("devices/system/memory/block_size_bytes",
148662306a36Sopenharmony_ci			      (unsigned long long *) &bsize);
148762306a36Sopenharmony_ci	if (ret)
148862306a36Sopenharmony_ci		return ret;
148962306a36Sopenharmony_ci
149062306a36Sopenharmony_ci	ret = build_mem_topology(&nodes, &nr);
149162306a36Sopenharmony_ci	if (ret)
149262306a36Sopenharmony_ci		return ret;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	ret = do_write(ff, &version, sizeof(version));
149562306a36Sopenharmony_ci	if (ret < 0)
149662306a36Sopenharmony_ci		goto out;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci	ret = do_write(ff, &bsize, sizeof(bsize));
149962306a36Sopenharmony_ci	if (ret < 0)
150062306a36Sopenharmony_ci		goto out;
150162306a36Sopenharmony_ci
150262306a36Sopenharmony_ci	ret = do_write(ff, &nr, sizeof(nr));
150362306a36Sopenharmony_ci	if (ret < 0)
150462306a36Sopenharmony_ci		goto out;
150562306a36Sopenharmony_ci
150662306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
150762306a36Sopenharmony_ci		struct memory_node *n = &nodes[i];
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci		#define _W(v)						\
151062306a36Sopenharmony_ci			ret = do_write(ff, &n->v, sizeof(n->v));	\
151162306a36Sopenharmony_ci			if (ret < 0)					\
151262306a36Sopenharmony_ci				goto out;
151362306a36Sopenharmony_ci
151462306a36Sopenharmony_ci		_W(node)
151562306a36Sopenharmony_ci		_W(size)
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci		#undef _W
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci		ret = do_write_bitmap(ff, n->set, n->size);
152062306a36Sopenharmony_ci		if (ret < 0)
152162306a36Sopenharmony_ci			goto out;
152262306a36Sopenharmony_ci	}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ciout:
152562306a36Sopenharmony_ci	memory_node__delete_nodes(nodes, nr);
152662306a36Sopenharmony_ci	return ret;
152762306a36Sopenharmony_ci}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_cistatic int write_compressed(struct feat_fd *ff __maybe_unused,
153062306a36Sopenharmony_ci			    struct evlist *evlist __maybe_unused)
153162306a36Sopenharmony_ci{
153262306a36Sopenharmony_ci	int ret;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_ver), sizeof(ff->ph->env.comp_ver));
153562306a36Sopenharmony_ci	if (ret)
153662306a36Sopenharmony_ci		return ret;
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_type), sizeof(ff->ph->env.comp_type));
153962306a36Sopenharmony_ci	if (ret)
154062306a36Sopenharmony_ci		return ret;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_level), sizeof(ff->ph->env.comp_level));
154362306a36Sopenharmony_ci	if (ret)
154462306a36Sopenharmony_ci		return ret;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	ret = do_write(ff, &(ff->ph->env.comp_ratio), sizeof(ff->ph->env.comp_ratio));
154762306a36Sopenharmony_ci	if (ret)
154862306a36Sopenharmony_ci		return ret;
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len));
155162306a36Sopenharmony_ci}
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_cistatic int __write_pmu_caps(struct feat_fd *ff, struct perf_pmu *pmu,
155462306a36Sopenharmony_ci			    bool write_pmu)
155562306a36Sopenharmony_ci{
155662306a36Sopenharmony_ci	struct perf_pmu_caps *caps = NULL;
155762306a36Sopenharmony_ci	int ret;
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	ret = do_write(ff, &pmu->nr_caps, sizeof(pmu->nr_caps));
156062306a36Sopenharmony_ci	if (ret < 0)
156162306a36Sopenharmony_ci		return ret;
156262306a36Sopenharmony_ci
156362306a36Sopenharmony_ci	list_for_each_entry(caps, &pmu->caps, list) {
156462306a36Sopenharmony_ci		ret = do_write_string(ff, caps->name);
156562306a36Sopenharmony_ci		if (ret < 0)
156662306a36Sopenharmony_ci			return ret;
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci		ret = do_write_string(ff, caps->value);
156962306a36Sopenharmony_ci		if (ret < 0)
157062306a36Sopenharmony_ci			return ret;
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci
157362306a36Sopenharmony_ci	if (write_pmu) {
157462306a36Sopenharmony_ci		ret = do_write_string(ff, pmu->name);
157562306a36Sopenharmony_ci		if (ret < 0)
157662306a36Sopenharmony_ci			return ret;
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return ret;
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic int write_cpu_pmu_caps(struct feat_fd *ff,
158362306a36Sopenharmony_ci			      struct evlist *evlist __maybe_unused)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	struct perf_pmu *cpu_pmu = perf_pmus__find("cpu");
158662306a36Sopenharmony_ci	int ret;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (!cpu_pmu)
158962306a36Sopenharmony_ci		return -ENOENT;
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_ci	ret = perf_pmu__caps_parse(cpu_pmu);
159262306a36Sopenharmony_ci	if (ret < 0)
159362306a36Sopenharmony_ci		return ret;
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	return __write_pmu_caps(ff, cpu_pmu, false);
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_cistatic int write_pmu_caps(struct feat_fd *ff,
159962306a36Sopenharmony_ci			  struct evlist *evlist __maybe_unused)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	struct perf_pmu *pmu = NULL;
160262306a36Sopenharmony_ci	int nr_pmu = 0;
160362306a36Sopenharmony_ci	int ret;
160462306a36Sopenharmony_ci
160562306a36Sopenharmony_ci	while ((pmu = perf_pmus__scan(pmu))) {
160662306a36Sopenharmony_ci		if (!strcmp(pmu->name, "cpu")) {
160762306a36Sopenharmony_ci			/*
160862306a36Sopenharmony_ci			 * The "cpu" PMU is special and covered by
160962306a36Sopenharmony_ci			 * HEADER_CPU_PMU_CAPS. Note, core PMUs are
161062306a36Sopenharmony_ci			 * counted/written here for ARM, s390 and Intel hybrid.
161162306a36Sopenharmony_ci			 */
161262306a36Sopenharmony_ci			continue;
161362306a36Sopenharmony_ci		}
161462306a36Sopenharmony_ci		if (perf_pmu__caps_parse(pmu) <= 0)
161562306a36Sopenharmony_ci			continue;
161662306a36Sopenharmony_ci		nr_pmu++;
161762306a36Sopenharmony_ci	}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci	ret = do_write(ff, &nr_pmu, sizeof(nr_pmu));
162062306a36Sopenharmony_ci	if (ret < 0)
162162306a36Sopenharmony_ci		return ret;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	if (!nr_pmu)
162462306a36Sopenharmony_ci		return 0;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	/*
162762306a36Sopenharmony_ci	 * Note older perf tools assume core PMUs come first, this is a property
162862306a36Sopenharmony_ci	 * of perf_pmus__scan.
162962306a36Sopenharmony_ci	 */
163062306a36Sopenharmony_ci	pmu = NULL;
163162306a36Sopenharmony_ci	while ((pmu = perf_pmus__scan(pmu))) {
163262306a36Sopenharmony_ci		if (!strcmp(pmu->name, "cpu")) {
163362306a36Sopenharmony_ci			/* Skip as above. */
163462306a36Sopenharmony_ci			continue;
163562306a36Sopenharmony_ci		}
163662306a36Sopenharmony_ci		if (perf_pmu__caps_parse(pmu) <= 0)
163762306a36Sopenharmony_ci			continue;
163862306a36Sopenharmony_ci		ret = __write_pmu_caps(ff, pmu, true);
163962306a36Sopenharmony_ci		if (ret < 0)
164062306a36Sopenharmony_ci			return ret;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci	return 0;
164362306a36Sopenharmony_ci}
164462306a36Sopenharmony_ci
164562306a36Sopenharmony_cistatic void print_hostname(struct feat_fd *ff, FILE *fp)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
164862306a36Sopenharmony_ci}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_cistatic void print_osrelease(struct feat_fd *ff, FILE *fp)
165162306a36Sopenharmony_ci{
165262306a36Sopenharmony_ci	fprintf(fp, "# os release : %s\n", ff->ph->env.os_release);
165362306a36Sopenharmony_ci}
165462306a36Sopenharmony_ci
165562306a36Sopenharmony_cistatic void print_arch(struct feat_fd *ff, FILE *fp)
165662306a36Sopenharmony_ci{
165762306a36Sopenharmony_ci	fprintf(fp, "# arch : %s\n", ff->ph->env.arch);
165862306a36Sopenharmony_ci}
165962306a36Sopenharmony_ci
166062306a36Sopenharmony_cistatic void print_cpudesc(struct feat_fd *ff, FILE *fp)
166162306a36Sopenharmony_ci{
166262306a36Sopenharmony_ci	fprintf(fp, "# cpudesc : %s\n", ff->ph->env.cpu_desc);
166362306a36Sopenharmony_ci}
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_cistatic void print_nrcpus(struct feat_fd *ff, FILE *fp)
166662306a36Sopenharmony_ci{
166762306a36Sopenharmony_ci	fprintf(fp, "# nrcpus online : %u\n", ff->ph->env.nr_cpus_online);
166862306a36Sopenharmony_ci	fprintf(fp, "# nrcpus avail : %u\n", ff->ph->env.nr_cpus_avail);
166962306a36Sopenharmony_ci}
167062306a36Sopenharmony_ci
167162306a36Sopenharmony_cistatic void print_version(struct feat_fd *ff, FILE *fp)
167262306a36Sopenharmony_ci{
167362306a36Sopenharmony_ci	fprintf(fp, "# perf version : %s\n", ff->ph->env.version);
167462306a36Sopenharmony_ci}
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_cistatic void print_cmdline(struct feat_fd *ff, FILE *fp)
167762306a36Sopenharmony_ci{
167862306a36Sopenharmony_ci	int nr, i;
167962306a36Sopenharmony_ci
168062306a36Sopenharmony_ci	nr = ff->ph->env.nr_cmdline;
168162306a36Sopenharmony_ci
168262306a36Sopenharmony_ci	fprintf(fp, "# cmdline : ");
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
168562306a36Sopenharmony_ci		char *argv_i = strdup(ff->ph->env.cmdline_argv[i]);
168662306a36Sopenharmony_ci		if (!argv_i) {
168762306a36Sopenharmony_ci			fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]);
168862306a36Sopenharmony_ci		} else {
168962306a36Sopenharmony_ci			char *mem = argv_i;
169062306a36Sopenharmony_ci			do {
169162306a36Sopenharmony_ci				char *quote = strchr(argv_i, '\'');
169262306a36Sopenharmony_ci				if (!quote)
169362306a36Sopenharmony_ci					break;
169462306a36Sopenharmony_ci				*quote++ = '\0';
169562306a36Sopenharmony_ci				fprintf(fp, "%s\\\'", argv_i);
169662306a36Sopenharmony_ci				argv_i = quote;
169762306a36Sopenharmony_ci			} while (1);
169862306a36Sopenharmony_ci			fprintf(fp, "%s ", argv_i);
169962306a36Sopenharmony_ci			free(mem);
170062306a36Sopenharmony_ci		}
170162306a36Sopenharmony_ci	}
170262306a36Sopenharmony_ci	fputc('\n', fp);
170362306a36Sopenharmony_ci}
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_cistatic void print_cpu_topology(struct feat_fd *ff, FILE *fp)
170662306a36Sopenharmony_ci{
170762306a36Sopenharmony_ci	struct perf_header *ph = ff->ph;
170862306a36Sopenharmony_ci	int cpu_nr = ph->env.nr_cpus_avail;
170962306a36Sopenharmony_ci	int nr, i;
171062306a36Sopenharmony_ci	char *str;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	nr = ph->env.nr_sibling_cores;
171362306a36Sopenharmony_ci	str = ph->env.sibling_cores;
171462306a36Sopenharmony_ci
171562306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
171662306a36Sopenharmony_ci		fprintf(fp, "# sibling sockets : %s\n", str);
171762306a36Sopenharmony_ci		str += strlen(str) + 1;
171862306a36Sopenharmony_ci	}
171962306a36Sopenharmony_ci
172062306a36Sopenharmony_ci	if (ph->env.nr_sibling_dies) {
172162306a36Sopenharmony_ci		nr = ph->env.nr_sibling_dies;
172262306a36Sopenharmony_ci		str = ph->env.sibling_dies;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci		for (i = 0; i < nr; i++) {
172562306a36Sopenharmony_ci			fprintf(fp, "# sibling dies    : %s\n", str);
172662306a36Sopenharmony_ci			str += strlen(str) + 1;
172762306a36Sopenharmony_ci		}
172862306a36Sopenharmony_ci	}
172962306a36Sopenharmony_ci
173062306a36Sopenharmony_ci	nr = ph->env.nr_sibling_threads;
173162306a36Sopenharmony_ci	str = ph->env.sibling_threads;
173262306a36Sopenharmony_ci
173362306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
173462306a36Sopenharmony_ci		fprintf(fp, "# sibling threads : %s\n", str);
173562306a36Sopenharmony_ci		str += strlen(str) + 1;
173662306a36Sopenharmony_ci	}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_ci	if (ph->env.nr_sibling_dies) {
173962306a36Sopenharmony_ci		if (ph->env.cpu != NULL) {
174062306a36Sopenharmony_ci			for (i = 0; i < cpu_nr; i++)
174162306a36Sopenharmony_ci				fprintf(fp, "# CPU %d: Core ID %d, "
174262306a36Sopenharmony_ci					    "Die ID %d, Socket ID %d\n",
174362306a36Sopenharmony_ci					    i, ph->env.cpu[i].core_id,
174462306a36Sopenharmony_ci					    ph->env.cpu[i].die_id,
174562306a36Sopenharmony_ci					    ph->env.cpu[i].socket_id);
174662306a36Sopenharmony_ci		} else
174762306a36Sopenharmony_ci			fprintf(fp, "# Core ID, Die ID and Socket ID "
174862306a36Sopenharmony_ci				    "information is not available\n");
174962306a36Sopenharmony_ci	} else {
175062306a36Sopenharmony_ci		if (ph->env.cpu != NULL) {
175162306a36Sopenharmony_ci			for (i = 0; i < cpu_nr; i++)
175262306a36Sopenharmony_ci				fprintf(fp, "# CPU %d: Core ID %d, "
175362306a36Sopenharmony_ci					    "Socket ID %d\n",
175462306a36Sopenharmony_ci					    i, ph->env.cpu[i].core_id,
175562306a36Sopenharmony_ci					    ph->env.cpu[i].socket_id);
175662306a36Sopenharmony_ci		} else
175762306a36Sopenharmony_ci			fprintf(fp, "# Core ID and Socket ID "
175862306a36Sopenharmony_ci				    "information is not available\n");
175962306a36Sopenharmony_ci	}
176062306a36Sopenharmony_ci}
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_cistatic void print_clockid(struct feat_fd *ff, FILE *fp)
176362306a36Sopenharmony_ci{
176462306a36Sopenharmony_ci	fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n",
176562306a36Sopenharmony_ci		ff->ph->env.clock.clockid_res_ns * 1000);
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_cistatic void print_clock_data(struct feat_fd *ff, FILE *fp)
176962306a36Sopenharmony_ci{
177062306a36Sopenharmony_ci	struct timespec clockid_ns;
177162306a36Sopenharmony_ci	char tstr[64], date[64];
177262306a36Sopenharmony_ci	struct timeval tod_ns;
177362306a36Sopenharmony_ci	clockid_t clockid;
177462306a36Sopenharmony_ci	struct tm ltime;
177562306a36Sopenharmony_ci	u64 ref;
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	if (!ff->ph->env.clock.enabled) {
177862306a36Sopenharmony_ci		fprintf(fp, "# reference time disabled\n");
177962306a36Sopenharmony_ci		return;
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci	/* Compute TOD time. */
178362306a36Sopenharmony_ci	ref = ff->ph->env.clock.tod_ns;
178462306a36Sopenharmony_ci	tod_ns.tv_sec = ref / NSEC_PER_SEC;
178562306a36Sopenharmony_ci	ref -= tod_ns.tv_sec * NSEC_PER_SEC;
178662306a36Sopenharmony_ci	tod_ns.tv_usec = ref / NSEC_PER_USEC;
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	/* Compute clockid time. */
178962306a36Sopenharmony_ci	ref = ff->ph->env.clock.clockid_ns;
179062306a36Sopenharmony_ci	clockid_ns.tv_sec = ref / NSEC_PER_SEC;
179162306a36Sopenharmony_ci	ref -= clockid_ns.tv_sec * NSEC_PER_SEC;
179262306a36Sopenharmony_ci	clockid_ns.tv_nsec = ref;
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	clockid = ff->ph->env.clock.clockid;
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	if (localtime_r(&tod_ns.tv_sec, &ltime) == NULL)
179762306a36Sopenharmony_ci		snprintf(tstr, sizeof(tstr), "<error>");
179862306a36Sopenharmony_ci	else {
179962306a36Sopenharmony_ci		strftime(date, sizeof(date), "%F %T", &ltime);
180062306a36Sopenharmony_ci		scnprintf(tstr, sizeof(tstr), "%s.%06d",
180162306a36Sopenharmony_ci			  date, (int) tod_ns.tv_usec);
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	fprintf(fp, "# clockid: %s (%u)\n", clockid_name(clockid), clockid);
180562306a36Sopenharmony_ci	fprintf(fp, "# reference time: %s = %ld.%06d (TOD) = %ld.%09ld (%s)\n",
180662306a36Sopenharmony_ci		    tstr, (long) tod_ns.tv_sec, (int) tod_ns.tv_usec,
180762306a36Sopenharmony_ci		    (long) clockid_ns.tv_sec, clockid_ns.tv_nsec,
180862306a36Sopenharmony_ci		    clockid_name(clockid));
180962306a36Sopenharmony_ci}
181062306a36Sopenharmony_ci
181162306a36Sopenharmony_cistatic void print_hybrid_topology(struct feat_fd *ff, FILE *fp)
181262306a36Sopenharmony_ci{
181362306a36Sopenharmony_ci	int i;
181462306a36Sopenharmony_ci	struct hybrid_node *n;
181562306a36Sopenharmony_ci
181662306a36Sopenharmony_ci	fprintf(fp, "# hybrid cpu system:\n");
181762306a36Sopenharmony_ci	for (i = 0; i < ff->ph->env.nr_hybrid_nodes; i++) {
181862306a36Sopenharmony_ci		n = &ff->ph->env.hybrid_nodes[i];
181962306a36Sopenharmony_ci		fprintf(fp, "# %s cpu list : %s\n", n->pmu_name, n->cpus);
182062306a36Sopenharmony_ci	}
182162306a36Sopenharmony_ci}
182262306a36Sopenharmony_ci
182362306a36Sopenharmony_cistatic void print_dir_format(struct feat_fd *ff, FILE *fp)
182462306a36Sopenharmony_ci{
182562306a36Sopenharmony_ci	struct perf_session *session;
182662306a36Sopenharmony_ci	struct perf_data *data;
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
182962306a36Sopenharmony_ci	data = session->data;
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version);
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
183562306a36Sopenharmony_cistatic void print_bpf_prog_info(struct feat_fd *ff, FILE *fp)
183662306a36Sopenharmony_ci{
183762306a36Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
183862306a36Sopenharmony_ci	struct rb_root *root;
183962306a36Sopenharmony_ci	struct rb_node *next;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	down_read(&env->bpf_progs.lock);
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	root = &env->bpf_progs.infos;
184462306a36Sopenharmony_ci	next = rb_first(root);
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	while (next) {
184762306a36Sopenharmony_ci		struct bpf_prog_info_node *node;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		node = rb_entry(next, struct bpf_prog_info_node, rb_node);
185062306a36Sopenharmony_ci		next = rb_next(&node->rb_node);
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci		__bpf_event__print_bpf_prog_info(&node->info_linear->info,
185362306a36Sopenharmony_ci						 env, fp);
185462306a36Sopenharmony_ci	}
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ci	up_read(&env->bpf_progs.lock);
185762306a36Sopenharmony_ci}
185862306a36Sopenharmony_ci
185962306a36Sopenharmony_cistatic void print_bpf_btf(struct feat_fd *ff, FILE *fp)
186062306a36Sopenharmony_ci{
186162306a36Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
186262306a36Sopenharmony_ci	struct rb_root *root;
186362306a36Sopenharmony_ci	struct rb_node *next;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	down_read(&env->bpf_progs.lock);
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	root = &env->bpf_progs.btfs;
186862306a36Sopenharmony_ci	next = rb_first(root);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	while (next) {
187162306a36Sopenharmony_ci		struct btf_node *node;
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ci		node = rb_entry(next, struct btf_node, rb_node);
187462306a36Sopenharmony_ci		next = rb_next(&node->rb_node);
187562306a36Sopenharmony_ci		fprintf(fp, "# btf info of id %u\n", node->id);
187662306a36Sopenharmony_ci	}
187762306a36Sopenharmony_ci
187862306a36Sopenharmony_ci	up_read(&env->bpf_progs.lock);
187962306a36Sopenharmony_ci}
188062306a36Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_cistatic void free_event_desc(struct evsel *events)
188362306a36Sopenharmony_ci{
188462306a36Sopenharmony_ci	struct evsel *evsel;
188562306a36Sopenharmony_ci
188662306a36Sopenharmony_ci	if (!events)
188762306a36Sopenharmony_ci		return;
188862306a36Sopenharmony_ci
188962306a36Sopenharmony_ci	for (evsel = events; evsel->core.attr.size; evsel++) {
189062306a36Sopenharmony_ci		zfree(&evsel->name);
189162306a36Sopenharmony_ci		zfree(&evsel->core.id);
189262306a36Sopenharmony_ci	}
189362306a36Sopenharmony_ci
189462306a36Sopenharmony_ci	free(events);
189562306a36Sopenharmony_ci}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_cistatic bool perf_attr_check(struct perf_event_attr *attr)
189862306a36Sopenharmony_ci{
189962306a36Sopenharmony_ci	if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) {
190062306a36Sopenharmony_ci		pr_warning("Reserved bits are set unexpectedly. "
190162306a36Sopenharmony_ci			   "Please update perf tool.\n");
190262306a36Sopenharmony_ci		return false;
190362306a36Sopenharmony_ci	}
190462306a36Sopenharmony_ci
190562306a36Sopenharmony_ci	if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) {
190662306a36Sopenharmony_ci		pr_warning("Unknown sample type (0x%llx) is detected. "
190762306a36Sopenharmony_ci			   "Please update perf tool.\n",
190862306a36Sopenharmony_ci			   attr->sample_type);
190962306a36Sopenharmony_ci		return false;
191062306a36Sopenharmony_ci	}
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	if (attr->read_format & ~(PERF_FORMAT_MAX-1)) {
191362306a36Sopenharmony_ci		pr_warning("Unknown read format (0x%llx) is detected. "
191462306a36Sopenharmony_ci			   "Please update perf tool.\n",
191562306a36Sopenharmony_ci			   attr->read_format);
191662306a36Sopenharmony_ci		return false;
191762306a36Sopenharmony_ci	}
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	if ((attr->sample_type & PERF_SAMPLE_BRANCH_STACK) &&
192062306a36Sopenharmony_ci	    (attr->branch_sample_type & ~(PERF_SAMPLE_BRANCH_MAX-1))) {
192162306a36Sopenharmony_ci		pr_warning("Unknown branch sample type (0x%llx) is detected. "
192262306a36Sopenharmony_ci			   "Please update perf tool.\n",
192362306a36Sopenharmony_ci			   attr->branch_sample_type);
192462306a36Sopenharmony_ci
192562306a36Sopenharmony_ci		return false;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci
192862306a36Sopenharmony_ci	return true;
192962306a36Sopenharmony_ci}
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_cistatic struct evsel *read_event_desc(struct feat_fd *ff)
193262306a36Sopenharmony_ci{
193362306a36Sopenharmony_ci	struct evsel *evsel, *events = NULL;
193462306a36Sopenharmony_ci	u64 *id;
193562306a36Sopenharmony_ci	void *buf = NULL;
193662306a36Sopenharmony_ci	u32 nre, sz, nr, i, j;
193762306a36Sopenharmony_ci	size_t msz;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	/* number of events */
194062306a36Sopenharmony_ci	if (do_read_u32(ff, &nre))
194162306a36Sopenharmony_ci		goto error;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	if (do_read_u32(ff, &sz))
194462306a36Sopenharmony_ci		goto error;
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	/* buffer to hold on file attr struct */
194762306a36Sopenharmony_ci	buf = malloc(sz);
194862306a36Sopenharmony_ci	if (!buf)
194962306a36Sopenharmony_ci		goto error;
195062306a36Sopenharmony_ci
195162306a36Sopenharmony_ci	/* the last event terminates with evsel->core.attr.size == 0: */
195262306a36Sopenharmony_ci	events = calloc(nre + 1, sizeof(*events));
195362306a36Sopenharmony_ci	if (!events)
195462306a36Sopenharmony_ci		goto error;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	msz = sizeof(evsel->core.attr);
195762306a36Sopenharmony_ci	if (sz < msz)
195862306a36Sopenharmony_ci		msz = sz;
195962306a36Sopenharmony_ci
196062306a36Sopenharmony_ci	for (i = 0, evsel = events; i < nre; evsel++, i++) {
196162306a36Sopenharmony_ci		evsel->core.idx = i;
196262306a36Sopenharmony_ci
196362306a36Sopenharmony_ci		/*
196462306a36Sopenharmony_ci		 * must read entire on-file attr struct to
196562306a36Sopenharmony_ci		 * sync up with layout.
196662306a36Sopenharmony_ci		 */
196762306a36Sopenharmony_ci		if (__do_read(ff, buf, sz))
196862306a36Sopenharmony_ci			goto error;
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci		if (ff->ph->needs_swap)
197162306a36Sopenharmony_ci			perf_event__attr_swap(buf);
197262306a36Sopenharmony_ci
197362306a36Sopenharmony_ci		memcpy(&evsel->core.attr, buf, msz);
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci		if (!perf_attr_check(&evsel->core.attr))
197662306a36Sopenharmony_ci			goto error;
197762306a36Sopenharmony_ci
197862306a36Sopenharmony_ci		if (do_read_u32(ff, &nr))
197962306a36Sopenharmony_ci			goto error;
198062306a36Sopenharmony_ci
198162306a36Sopenharmony_ci		if (ff->ph->needs_swap)
198262306a36Sopenharmony_ci			evsel->needs_swap = true;
198362306a36Sopenharmony_ci
198462306a36Sopenharmony_ci		evsel->name = do_read_string(ff);
198562306a36Sopenharmony_ci		if (!evsel->name)
198662306a36Sopenharmony_ci			goto error;
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci		if (!nr)
198962306a36Sopenharmony_ci			continue;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci		id = calloc(nr, sizeof(*id));
199262306a36Sopenharmony_ci		if (!id)
199362306a36Sopenharmony_ci			goto error;
199462306a36Sopenharmony_ci		evsel->core.ids = nr;
199562306a36Sopenharmony_ci		evsel->core.id = id;
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci		for (j = 0 ; j < nr; j++) {
199862306a36Sopenharmony_ci			if (do_read_u64(ff, id))
199962306a36Sopenharmony_ci				goto error;
200062306a36Sopenharmony_ci			id++;
200162306a36Sopenharmony_ci		}
200262306a36Sopenharmony_ci	}
200362306a36Sopenharmony_ciout:
200462306a36Sopenharmony_ci	free(buf);
200562306a36Sopenharmony_ci	return events;
200662306a36Sopenharmony_cierror:
200762306a36Sopenharmony_ci	free_event_desc(events);
200862306a36Sopenharmony_ci	events = NULL;
200962306a36Sopenharmony_ci	goto out;
201062306a36Sopenharmony_ci}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_cistatic int __desc_attr__fprintf(FILE *fp, const char *name, const char *val,
201362306a36Sopenharmony_ci				void *priv __maybe_unused)
201462306a36Sopenharmony_ci{
201562306a36Sopenharmony_ci	return fprintf(fp, ", %s = %s", name, val);
201662306a36Sopenharmony_ci}
201762306a36Sopenharmony_ci
201862306a36Sopenharmony_cistatic void print_event_desc(struct feat_fd *ff, FILE *fp)
201962306a36Sopenharmony_ci{
202062306a36Sopenharmony_ci	struct evsel *evsel, *events;
202162306a36Sopenharmony_ci	u32 j;
202262306a36Sopenharmony_ci	u64 *id;
202362306a36Sopenharmony_ci
202462306a36Sopenharmony_ci	if (ff->events)
202562306a36Sopenharmony_ci		events = ff->events;
202662306a36Sopenharmony_ci	else
202762306a36Sopenharmony_ci		events = read_event_desc(ff);
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	if (!events) {
203062306a36Sopenharmony_ci		fprintf(fp, "# event desc: not available or unable to read\n");
203162306a36Sopenharmony_ci		return;
203262306a36Sopenharmony_ci	}
203362306a36Sopenharmony_ci
203462306a36Sopenharmony_ci	for (evsel = events; evsel->core.attr.size; evsel++) {
203562306a36Sopenharmony_ci		fprintf(fp, "# event : name = %s, ", evsel->name);
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci		if (evsel->core.ids) {
203862306a36Sopenharmony_ci			fprintf(fp, ", id = {");
203962306a36Sopenharmony_ci			for (j = 0, id = evsel->core.id; j < evsel->core.ids; j++, id++) {
204062306a36Sopenharmony_ci				if (j)
204162306a36Sopenharmony_ci					fputc(',', fp);
204262306a36Sopenharmony_ci				fprintf(fp, " %"PRIu64, *id);
204362306a36Sopenharmony_ci			}
204462306a36Sopenharmony_ci			fprintf(fp, " }");
204562306a36Sopenharmony_ci		}
204662306a36Sopenharmony_ci
204762306a36Sopenharmony_ci		perf_event_attr__fprintf(fp, &evsel->core.attr, __desc_attr__fprintf, NULL);
204862306a36Sopenharmony_ci
204962306a36Sopenharmony_ci		fputc('\n', fp);
205062306a36Sopenharmony_ci	}
205162306a36Sopenharmony_ci
205262306a36Sopenharmony_ci	free_event_desc(events);
205362306a36Sopenharmony_ci	ff->events = NULL;
205462306a36Sopenharmony_ci}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_cistatic void print_total_mem(struct feat_fd *ff, FILE *fp)
205762306a36Sopenharmony_ci{
205862306a36Sopenharmony_ci	fprintf(fp, "# total memory : %llu kB\n", ff->ph->env.total_mem);
205962306a36Sopenharmony_ci}
206062306a36Sopenharmony_ci
206162306a36Sopenharmony_cistatic void print_numa_topology(struct feat_fd *ff, FILE *fp)
206262306a36Sopenharmony_ci{
206362306a36Sopenharmony_ci	int i;
206462306a36Sopenharmony_ci	struct numa_node *n;
206562306a36Sopenharmony_ci
206662306a36Sopenharmony_ci	for (i = 0; i < ff->ph->env.nr_numa_nodes; i++) {
206762306a36Sopenharmony_ci		n = &ff->ph->env.numa_nodes[i];
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci		fprintf(fp, "# node%u meminfo  : total = %"PRIu64" kB,"
207062306a36Sopenharmony_ci			    " free = %"PRIu64" kB\n",
207162306a36Sopenharmony_ci			n->node, n->mem_total, n->mem_free);
207262306a36Sopenharmony_ci
207362306a36Sopenharmony_ci		fprintf(fp, "# node%u cpu list : ", n->node);
207462306a36Sopenharmony_ci		cpu_map__fprintf(n->map, fp);
207562306a36Sopenharmony_ci	}
207662306a36Sopenharmony_ci}
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_cistatic void print_cpuid(struct feat_fd *ff, FILE *fp)
207962306a36Sopenharmony_ci{
208062306a36Sopenharmony_ci	fprintf(fp, "# cpuid : %s\n", ff->ph->env.cpuid);
208162306a36Sopenharmony_ci}
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_cistatic void print_branch_stack(struct feat_fd *ff __maybe_unused, FILE *fp)
208462306a36Sopenharmony_ci{
208562306a36Sopenharmony_ci	fprintf(fp, "# contains samples with branch stack\n");
208662306a36Sopenharmony_ci}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_cistatic void print_auxtrace(struct feat_fd *ff __maybe_unused, FILE *fp)
208962306a36Sopenharmony_ci{
209062306a36Sopenharmony_ci	fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n");
209162306a36Sopenharmony_ci}
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_cistatic void print_stat(struct feat_fd *ff __maybe_unused, FILE *fp)
209462306a36Sopenharmony_ci{
209562306a36Sopenharmony_ci	fprintf(fp, "# contains stat data\n");
209662306a36Sopenharmony_ci}
209762306a36Sopenharmony_ci
209862306a36Sopenharmony_cistatic void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused)
209962306a36Sopenharmony_ci{
210062306a36Sopenharmony_ci	int i;
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci	fprintf(fp, "# CPU cache info:\n");
210362306a36Sopenharmony_ci	for (i = 0; i < ff->ph->env.caches_cnt; i++) {
210462306a36Sopenharmony_ci		fprintf(fp, "#  ");
210562306a36Sopenharmony_ci		cpu_cache_level__fprintf(fp, &ff->ph->env.caches[i]);
210662306a36Sopenharmony_ci	}
210762306a36Sopenharmony_ci}
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_cistatic void print_compressed(struct feat_fd *ff, FILE *fp)
211062306a36Sopenharmony_ci{
211162306a36Sopenharmony_ci	fprintf(fp, "# compressed : %s, level = %d, ratio = %d\n",
211262306a36Sopenharmony_ci		ff->ph->env.comp_type == PERF_COMP_ZSTD ? "Zstd" : "Unknown",
211362306a36Sopenharmony_ci		ff->ph->env.comp_level, ff->ph->env.comp_ratio);
211462306a36Sopenharmony_ci}
211562306a36Sopenharmony_ci
211662306a36Sopenharmony_cistatic void __print_pmu_caps(FILE *fp, int nr_caps, char **caps, char *pmu_name)
211762306a36Sopenharmony_ci{
211862306a36Sopenharmony_ci	const char *delimiter = "";
211962306a36Sopenharmony_ci	int i;
212062306a36Sopenharmony_ci
212162306a36Sopenharmony_ci	if (!nr_caps) {
212262306a36Sopenharmony_ci		fprintf(fp, "# %s pmu capabilities: not available\n", pmu_name);
212362306a36Sopenharmony_ci		return;
212462306a36Sopenharmony_ci	}
212562306a36Sopenharmony_ci
212662306a36Sopenharmony_ci	fprintf(fp, "# %s pmu capabilities: ", pmu_name);
212762306a36Sopenharmony_ci	for (i = 0; i < nr_caps; i++) {
212862306a36Sopenharmony_ci		fprintf(fp, "%s%s", delimiter, caps[i]);
212962306a36Sopenharmony_ci		delimiter = ", ";
213062306a36Sopenharmony_ci	}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_ci	fprintf(fp, "\n");
213362306a36Sopenharmony_ci}
213462306a36Sopenharmony_ci
213562306a36Sopenharmony_cistatic void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp)
213662306a36Sopenharmony_ci{
213762306a36Sopenharmony_ci	__print_pmu_caps(fp, ff->ph->env.nr_cpu_pmu_caps,
213862306a36Sopenharmony_ci			 ff->ph->env.cpu_pmu_caps, (char *)"cpu");
213962306a36Sopenharmony_ci}
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_cistatic void print_pmu_caps(struct feat_fd *ff, FILE *fp)
214262306a36Sopenharmony_ci{
214362306a36Sopenharmony_ci	struct pmu_caps *pmu_caps;
214462306a36Sopenharmony_ci
214562306a36Sopenharmony_ci	for (int i = 0; i < ff->ph->env.nr_pmus_with_caps; i++) {
214662306a36Sopenharmony_ci		pmu_caps = &ff->ph->env.pmu_caps[i];
214762306a36Sopenharmony_ci		__print_pmu_caps(fp, pmu_caps->nr_caps, pmu_caps->caps,
214862306a36Sopenharmony_ci				 pmu_caps->pmu_name);
214962306a36Sopenharmony_ci	}
215062306a36Sopenharmony_ci}
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_cistatic void print_pmu_mappings(struct feat_fd *ff, FILE *fp)
215362306a36Sopenharmony_ci{
215462306a36Sopenharmony_ci	const char *delimiter = "# pmu mappings: ";
215562306a36Sopenharmony_ci	char *str, *tmp;
215662306a36Sopenharmony_ci	u32 pmu_num;
215762306a36Sopenharmony_ci	u32 type;
215862306a36Sopenharmony_ci
215962306a36Sopenharmony_ci	pmu_num = ff->ph->env.nr_pmu_mappings;
216062306a36Sopenharmony_ci	if (!pmu_num) {
216162306a36Sopenharmony_ci		fprintf(fp, "# pmu mappings: not available\n");
216262306a36Sopenharmony_ci		return;
216362306a36Sopenharmony_ci	}
216462306a36Sopenharmony_ci
216562306a36Sopenharmony_ci	str = ff->ph->env.pmu_mappings;
216662306a36Sopenharmony_ci
216762306a36Sopenharmony_ci	while (pmu_num) {
216862306a36Sopenharmony_ci		type = strtoul(str, &tmp, 0);
216962306a36Sopenharmony_ci		if (*tmp != ':')
217062306a36Sopenharmony_ci			goto error;
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci		str = tmp + 1;
217362306a36Sopenharmony_ci		fprintf(fp, "%s%s = %" PRIu32, delimiter, str, type);
217462306a36Sopenharmony_ci
217562306a36Sopenharmony_ci		delimiter = ", ";
217662306a36Sopenharmony_ci		str += strlen(str) + 1;
217762306a36Sopenharmony_ci		pmu_num--;
217862306a36Sopenharmony_ci	}
217962306a36Sopenharmony_ci
218062306a36Sopenharmony_ci	fprintf(fp, "\n");
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	if (!pmu_num)
218362306a36Sopenharmony_ci		return;
218462306a36Sopenharmony_cierror:
218562306a36Sopenharmony_ci	fprintf(fp, "# pmu mappings: unable to read\n");
218662306a36Sopenharmony_ci}
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_cistatic void print_group_desc(struct feat_fd *ff, FILE *fp)
218962306a36Sopenharmony_ci{
219062306a36Sopenharmony_ci	struct perf_session *session;
219162306a36Sopenharmony_ci	struct evsel *evsel;
219262306a36Sopenharmony_ci	u32 nr = 0;
219362306a36Sopenharmony_ci
219462306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
219762306a36Sopenharmony_ci		if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) {
219862306a36Sopenharmony_ci			fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", evsel__name(evsel));
219962306a36Sopenharmony_ci
220062306a36Sopenharmony_ci			nr = evsel->core.nr_members - 1;
220162306a36Sopenharmony_ci		} else if (nr) {
220262306a36Sopenharmony_ci			fprintf(fp, ",%s", evsel__name(evsel));
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci			if (--nr == 0)
220562306a36Sopenharmony_ci				fprintf(fp, "}\n");
220662306a36Sopenharmony_ci		}
220762306a36Sopenharmony_ci	}
220862306a36Sopenharmony_ci}
220962306a36Sopenharmony_ci
221062306a36Sopenharmony_cistatic void print_sample_time(struct feat_fd *ff, FILE *fp)
221162306a36Sopenharmony_ci{
221262306a36Sopenharmony_ci	struct perf_session *session;
221362306a36Sopenharmony_ci	char time_buf[32];
221462306a36Sopenharmony_ci	double d;
221562306a36Sopenharmony_ci
221662306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
221762306a36Sopenharmony_ci
221862306a36Sopenharmony_ci	timestamp__scnprintf_usec(session->evlist->first_sample_time,
221962306a36Sopenharmony_ci				  time_buf, sizeof(time_buf));
222062306a36Sopenharmony_ci	fprintf(fp, "# time of first sample : %s\n", time_buf);
222162306a36Sopenharmony_ci
222262306a36Sopenharmony_ci	timestamp__scnprintf_usec(session->evlist->last_sample_time,
222362306a36Sopenharmony_ci				  time_buf, sizeof(time_buf));
222462306a36Sopenharmony_ci	fprintf(fp, "# time of last sample : %s\n", time_buf);
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	d = (double)(session->evlist->last_sample_time -
222762306a36Sopenharmony_ci		session->evlist->first_sample_time) / NSEC_PER_MSEC;
222862306a36Sopenharmony_ci
222962306a36Sopenharmony_ci	fprintf(fp, "# sample duration : %10.3f ms\n", d);
223062306a36Sopenharmony_ci}
223162306a36Sopenharmony_ci
223262306a36Sopenharmony_cistatic void memory_node__fprintf(struct memory_node *n,
223362306a36Sopenharmony_ci				 unsigned long long bsize, FILE *fp)
223462306a36Sopenharmony_ci{
223562306a36Sopenharmony_ci	char buf_map[100], buf_size[50];
223662306a36Sopenharmony_ci	unsigned long long size;
223762306a36Sopenharmony_ci
223862306a36Sopenharmony_ci	size = bsize * bitmap_weight(n->set, n->size);
223962306a36Sopenharmony_ci	unit_number__scnprintf(buf_size, 50, size);
224062306a36Sopenharmony_ci
224162306a36Sopenharmony_ci	bitmap_scnprintf(n->set, n->size, buf_map, 100);
224262306a36Sopenharmony_ci	fprintf(fp, "#  %3" PRIu64 " [%s]: %s\n", n->node, buf_size, buf_map);
224362306a36Sopenharmony_ci}
224462306a36Sopenharmony_ci
224562306a36Sopenharmony_cistatic void print_mem_topology(struct feat_fd *ff, FILE *fp)
224662306a36Sopenharmony_ci{
224762306a36Sopenharmony_ci	struct memory_node *nodes;
224862306a36Sopenharmony_ci	int i, nr;
224962306a36Sopenharmony_ci
225062306a36Sopenharmony_ci	nodes = ff->ph->env.memory_nodes;
225162306a36Sopenharmony_ci	nr    = ff->ph->env.nr_memory_nodes;
225262306a36Sopenharmony_ci
225362306a36Sopenharmony_ci	fprintf(fp, "# memory nodes (nr %d, block size 0x%llx):\n",
225462306a36Sopenharmony_ci		nr, ff->ph->env.memory_bsize);
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
225762306a36Sopenharmony_ci		memory_node__fprintf(&nodes[i], ff->ph->env.memory_bsize, fp);
225862306a36Sopenharmony_ci	}
225962306a36Sopenharmony_ci}
226062306a36Sopenharmony_ci
226162306a36Sopenharmony_cistatic int __event_process_build_id(struct perf_record_header_build_id *bev,
226262306a36Sopenharmony_ci				    char *filename,
226362306a36Sopenharmony_ci				    struct perf_session *session)
226462306a36Sopenharmony_ci{
226562306a36Sopenharmony_ci	int err = -1;
226662306a36Sopenharmony_ci	struct machine *machine;
226762306a36Sopenharmony_ci	u16 cpumode;
226862306a36Sopenharmony_ci	struct dso *dso;
226962306a36Sopenharmony_ci	enum dso_space_type dso_space;
227062306a36Sopenharmony_ci
227162306a36Sopenharmony_ci	machine = perf_session__findnew_machine(session, bev->pid);
227262306a36Sopenharmony_ci	if (!machine)
227362306a36Sopenharmony_ci		goto out;
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci	cpumode = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	switch (cpumode) {
227862306a36Sopenharmony_ci	case PERF_RECORD_MISC_KERNEL:
227962306a36Sopenharmony_ci		dso_space = DSO_SPACE__KERNEL;
228062306a36Sopenharmony_ci		break;
228162306a36Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_KERNEL:
228262306a36Sopenharmony_ci		dso_space = DSO_SPACE__KERNEL_GUEST;
228362306a36Sopenharmony_ci		break;
228462306a36Sopenharmony_ci	case PERF_RECORD_MISC_USER:
228562306a36Sopenharmony_ci	case PERF_RECORD_MISC_GUEST_USER:
228662306a36Sopenharmony_ci		dso_space = DSO_SPACE__USER;
228762306a36Sopenharmony_ci		break;
228862306a36Sopenharmony_ci	default:
228962306a36Sopenharmony_ci		goto out;
229062306a36Sopenharmony_ci	}
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	dso = machine__findnew_dso(machine, filename);
229362306a36Sopenharmony_ci	if (dso != NULL) {
229462306a36Sopenharmony_ci		char sbuild_id[SBUILD_ID_SIZE];
229562306a36Sopenharmony_ci		struct build_id bid;
229662306a36Sopenharmony_ci		size_t size = BUILD_ID_SIZE;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci		if (bev->header.misc & PERF_RECORD_MISC_BUILD_ID_SIZE)
229962306a36Sopenharmony_ci			size = bev->size;
230062306a36Sopenharmony_ci
230162306a36Sopenharmony_ci		build_id__init(&bid, bev->data, size);
230262306a36Sopenharmony_ci		dso__set_build_id(dso, &bid);
230362306a36Sopenharmony_ci		dso->header_build_id = 1;
230462306a36Sopenharmony_ci
230562306a36Sopenharmony_ci		if (dso_space != DSO_SPACE__USER) {
230662306a36Sopenharmony_ci			struct kmod_path m = { .name = NULL, };
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_ci			if (!kmod_path__parse_name(&m, filename) && m.kmod)
230962306a36Sopenharmony_ci				dso__set_module_info(dso, &m, machine);
231062306a36Sopenharmony_ci
231162306a36Sopenharmony_ci			dso->kernel = dso_space;
231262306a36Sopenharmony_ci			free(m.name);
231362306a36Sopenharmony_ci		}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci		build_id__sprintf(&dso->bid, sbuild_id);
231662306a36Sopenharmony_ci		pr_debug("build id event received for %s: %s [%zu]\n",
231762306a36Sopenharmony_ci			 dso->long_name, sbuild_id, size);
231862306a36Sopenharmony_ci		dso__put(dso);
231962306a36Sopenharmony_ci	}
232062306a36Sopenharmony_ci
232162306a36Sopenharmony_ci	err = 0;
232262306a36Sopenharmony_ciout:
232362306a36Sopenharmony_ci	return err;
232462306a36Sopenharmony_ci}
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_cistatic int perf_header__read_build_ids_abi_quirk(struct perf_header *header,
232762306a36Sopenharmony_ci						 int input, u64 offset, u64 size)
232862306a36Sopenharmony_ci{
232962306a36Sopenharmony_ci	struct perf_session *session = container_of(header, struct perf_session, header);
233062306a36Sopenharmony_ci	struct {
233162306a36Sopenharmony_ci		struct perf_event_header   header;
233262306a36Sopenharmony_ci		u8			   build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))];
233362306a36Sopenharmony_ci		char			   filename[0];
233462306a36Sopenharmony_ci	} old_bev;
233562306a36Sopenharmony_ci	struct perf_record_header_build_id bev;
233662306a36Sopenharmony_ci	char filename[PATH_MAX];
233762306a36Sopenharmony_ci	u64 limit = offset + size;
233862306a36Sopenharmony_ci
233962306a36Sopenharmony_ci	while (offset < limit) {
234062306a36Sopenharmony_ci		ssize_t len;
234162306a36Sopenharmony_ci
234262306a36Sopenharmony_ci		if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev))
234362306a36Sopenharmony_ci			return -1;
234462306a36Sopenharmony_ci
234562306a36Sopenharmony_ci		if (header->needs_swap)
234662306a36Sopenharmony_ci			perf_event_header__bswap(&old_bev.header);
234762306a36Sopenharmony_ci
234862306a36Sopenharmony_ci		len = old_bev.header.size - sizeof(old_bev);
234962306a36Sopenharmony_ci		if (readn(input, filename, len) != len)
235062306a36Sopenharmony_ci			return -1;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci		bev.header = old_bev.header;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci		/*
235562306a36Sopenharmony_ci		 * As the pid is the missing value, we need to fill
235662306a36Sopenharmony_ci		 * it properly. The header.misc value give us nice hint.
235762306a36Sopenharmony_ci		 */
235862306a36Sopenharmony_ci		bev.pid	= HOST_KERNEL_ID;
235962306a36Sopenharmony_ci		if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER ||
236062306a36Sopenharmony_ci		    bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL)
236162306a36Sopenharmony_ci			bev.pid	= DEFAULT_GUEST_KERNEL_ID;
236262306a36Sopenharmony_ci
236362306a36Sopenharmony_ci		memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id));
236462306a36Sopenharmony_ci		__event_process_build_id(&bev, filename, session);
236562306a36Sopenharmony_ci
236662306a36Sopenharmony_ci		offset += bev.header.size;
236762306a36Sopenharmony_ci	}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	return 0;
237062306a36Sopenharmony_ci}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_cistatic int perf_header__read_build_ids(struct perf_header *header,
237362306a36Sopenharmony_ci				       int input, u64 offset, u64 size)
237462306a36Sopenharmony_ci{
237562306a36Sopenharmony_ci	struct perf_session *session = container_of(header, struct perf_session, header);
237662306a36Sopenharmony_ci	struct perf_record_header_build_id bev;
237762306a36Sopenharmony_ci	char filename[PATH_MAX];
237862306a36Sopenharmony_ci	u64 limit = offset + size, orig_offset = offset;
237962306a36Sopenharmony_ci	int err = -1;
238062306a36Sopenharmony_ci
238162306a36Sopenharmony_ci	while (offset < limit) {
238262306a36Sopenharmony_ci		ssize_t len;
238362306a36Sopenharmony_ci
238462306a36Sopenharmony_ci		if (readn(input, &bev, sizeof(bev)) != sizeof(bev))
238562306a36Sopenharmony_ci			goto out;
238662306a36Sopenharmony_ci
238762306a36Sopenharmony_ci		if (header->needs_swap)
238862306a36Sopenharmony_ci			perf_event_header__bswap(&bev.header);
238962306a36Sopenharmony_ci
239062306a36Sopenharmony_ci		len = bev.header.size - sizeof(bev);
239162306a36Sopenharmony_ci		if (readn(input, filename, len) != len)
239262306a36Sopenharmony_ci			goto out;
239362306a36Sopenharmony_ci		/*
239462306a36Sopenharmony_ci		 * The a1645ce1 changeset:
239562306a36Sopenharmony_ci		 *
239662306a36Sopenharmony_ci		 * "perf: 'perf kvm' tool for monitoring guest performance from host"
239762306a36Sopenharmony_ci		 *
239862306a36Sopenharmony_ci		 * Added a field to struct perf_record_header_build_id that broke the file
239962306a36Sopenharmony_ci		 * format.
240062306a36Sopenharmony_ci		 *
240162306a36Sopenharmony_ci		 * Since the kernel build-id is the first entry, process the
240262306a36Sopenharmony_ci		 * table using the old format if the well known
240362306a36Sopenharmony_ci		 * '[kernel.kallsyms]' string for the kernel build-id has the
240462306a36Sopenharmony_ci		 * first 4 characters chopped off (where the pid_t sits).
240562306a36Sopenharmony_ci		 */
240662306a36Sopenharmony_ci		if (memcmp(filename, "nel.kallsyms]", 13) == 0) {
240762306a36Sopenharmony_ci			if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1)
240862306a36Sopenharmony_ci				return -1;
240962306a36Sopenharmony_ci			return perf_header__read_build_ids_abi_quirk(header, input, offset, size);
241062306a36Sopenharmony_ci		}
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci		__event_process_build_id(&bev, filename, session);
241362306a36Sopenharmony_ci
241462306a36Sopenharmony_ci		offset += bev.header.size;
241562306a36Sopenharmony_ci	}
241662306a36Sopenharmony_ci	err = 0;
241762306a36Sopenharmony_ciout:
241862306a36Sopenharmony_ci	return err;
241962306a36Sopenharmony_ci}
242062306a36Sopenharmony_ci
242162306a36Sopenharmony_ci/* Macro for features that simply need to read and store a string. */
242262306a36Sopenharmony_ci#define FEAT_PROCESS_STR_FUN(__feat, __feat_env) \
242362306a36Sopenharmony_cistatic int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \
242462306a36Sopenharmony_ci{\
242562306a36Sopenharmony_ci	free(ff->ph->env.__feat_env);		     \
242662306a36Sopenharmony_ci	ff->ph->env.__feat_env = do_read_string(ff); \
242762306a36Sopenharmony_ci	return ff->ph->env.__feat_env ? 0 : -ENOMEM; \
242862306a36Sopenharmony_ci}
242962306a36Sopenharmony_ci
243062306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(hostname, hostname);
243162306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(osrelease, os_release);
243262306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(version, version);
243362306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(arch, arch);
243462306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpudesc, cpu_desc);
243562306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpuid, cpuid);
243662306a36Sopenharmony_ci
243762306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
243862306a36Sopenharmony_cistatic int process_tracing_data(struct feat_fd *ff, void *data)
243962306a36Sopenharmony_ci{
244062306a36Sopenharmony_ci	ssize_t ret = trace_report(ff->fd, data, false);
244162306a36Sopenharmony_ci
244262306a36Sopenharmony_ci	return ret < 0 ? -1 : 0;
244362306a36Sopenharmony_ci}
244462306a36Sopenharmony_ci#endif
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_cistatic int process_build_id(struct feat_fd *ff, void *data __maybe_unused)
244762306a36Sopenharmony_ci{
244862306a36Sopenharmony_ci	if (perf_header__read_build_ids(ff->ph, ff->fd, ff->offset, ff->size))
244962306a36Sopenharmony_ci		pr_debug("Failed to read buildids, continuing...\n");
245062306a36Sopenharmony_ci	return 0;
245162306a36Sopenharmony_ci}
245262306a36Sopenharmony_ci
245362306a36Sopenharmony_cistatic int process_nrcpus(struct feat_fd *ff, void *data __maybe_unused)
245462306a36Sopenharmony_ci{
245562306a36Sopenharmony_ci	int ret;
245662306a36Sopenharmony_ci	u32 nr_cpus_avail, nr_cpus_online;
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_ci	ret = do_read_u32(ff, &nr_cpus_avail);
245962306a36Sopenharmony_ci	if (ret)
246062306a36Sopenharmony_ci		return ret;
246162306a36Sopenharmony_ci
246262306a36Sopenharmony_ci	ret = do_read_u32(ff, &nr_cpus_online);
246362306a36Sopenharmony_ci	if (ret)
246462306a36Sopenharmony_ci		return ret;
246562306a36Sopenharmony_ci	ff->ph->env.nr_cpus_avail = (int)nr_cpus_avail;
246662306a36Sopenharmony_ci	ff->ph->env.nr_cpus_online = (int)nr_cpus_online;
246762306a36Sopenharmony_ci	return 0;
246862306a36Sopenharmony_ci}
246962306a36Sopenharmony_ci
247062306a36Sopenharmony_cistatic int process_total_mem(struct feat_fd *ff, void *data __maybe_unused)
247162306a36Sopenharmony_ci{
247262306a36Sopenharmony_ci	u64 total_mem;
247362306a36Sopenharmony_ci	int ret;
247462306a36Sopenharmony_ci
247562306a36Sopenharmony_ci	ret = do_read_u64(ff, &total_mem);
247662306a36Sopenharmony_ci	if (ret)
247762306a36Sopenharmony_ci		return -1;
247862306a36Sopenharmony_ci	ff->ph->env.total_mem = (unsigned long long)total_mem;
247962306a36Sopenharmony_ci	return 0;
248062306a36Sopenharmony_ci}
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_cistatic struct evsel *evlist__find_by_index(struct evlist *evlist, int idx)
248362306a36Sopenharmony_ci{
248462306a36Sopenharmony_ci	struct evsel *evsel;
248562306a36Sopenharmony_ci
248662306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
248762306a36Sopenharmony_ci		if (evsel->core.idx == idx)
248862306a36Sopenharmony_ci			return evsel;
248962306a36Sopenharmony_ci	}
249062306a36Sopenharmony_ci
249162306a36Sopenharmony_ci	return NULL;
249262306a36Sopenharmony_ci}
249362306a36Sopenharmony_ci
249462306a36Sopenharmony_cistatic void evlist__set_event_name(struct evlist *evlist, struct evsel *event)
249562306a36Sopenharmony_ci{
249662306a36Sopenharmony_ci	struct evsel *evsel;
249762306a36Sopenharmony_ci
249862306a36Sopenharmony_ci	if (!event->name)
249962306a36Sopenharmony_ci		return;
250062306a36Sopenharmony_ci
250162306a36Sopenharmony_ci	evsel = evlist__find_by_index(evlist, event->core.idx);
250262306a36Sopenharmony_ci	if (!evsel)
250362306a36Sopenharmony_ci		return;
250462306a36Sopenharmony_ci
250562306a36Sopenharmony_ci	if (evsel->name)
250662306a36Sopenharmony_ci		return;
250762306a36Sopenharmony_ci
250862306a36Sopenharmony_ci	evsel->name = strdup(event->name);
250962306a36Sopenharmony_ci}
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_cistatic int
251262306a36Sopenharmony_ciprocess_event_desc(struct feat_fd *ff, void *data __maybe_unused)
251362306a36Sopenharmony_ci{
251462306a36Sopenharmony_ci	struct perf_session *session;
251562306a36Sopenharmony_ci	struct evsel *evsel, *events = read_event_desc(ff);
251662306a36Sopenharmony_ci
251762306a36Sopenharmony_ci	if (!events)
251862306a36Sopenharmony_ci		return 0;
251962306a36Sopenharmony_ci
252062306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
252162306a36Sopenharmony_ci
252262306a36Sopenharmony_ci	if (session->data->is_pipe) {
252362306a36Sopenharmony_ci		/* Save events for reading later by print_event_desc,
252462306a36Sopenharmony_ci		 * since they can't be read again in pipe mode. */
252562306a36Sopenharmony_ci		ff->events = events;
252662306a36Sopenharmony_ci	}
252762306a36Sopenharmony_ci
252862306a36Sopenharmony_ci	for (evsel = events; evsel->core.attr.size; evsel++)
252962306a36Sopenharmony_ci		evlist__set_event_name(session->evlist, evsel);
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	if (!session->data->is_pipe)
253262306a36Sopenharmony_ci		free_event_desc(events);
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	return 0;
253562306a36Sopenharmony_ci}
253662306a36Sopenharmony_ci
253762306a36Sopenharmony_cistatic int process_cmdline(struct feat_fd *ff, void *data __maybe_unused)
253862306a36Sopenharmony_ci{
253962306a36Sopenharmony_ci	char *str, *cmdline = NULL, **argv = NULL;
254062306a36Sopenharmony_ci	u32 nr, i, len = 0;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	if (do_read_u32(ff, &nr))
254362306a36Sopenharmony_ci		return -1;
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_ci	ff->ph->env.nr_cmdline = nr;
254662306a36Sopenharmony_ci
254762306a36Sopenharmony_ci	cmdline = zalloc(ff->size + nr + 1);
254862306a36Sopenharmony_ci	if (!cmdline)
254962306a36Sopenharmony_ci		return -1;
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci	argv = zalloc(sizeof(char *) * (nr + 1));
255262306a36Sopenharmony_ci	if (!argv)
255362306a36Sopenharmony_ci		goto error;
255462306a36Sopenharmony_ci
255562306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
255662306a36Sopenharmony_ci		str = do_read_string(ff);
255762306a36Sopenharmony_ci		if (!str)
255862306a36Sopenharmony_ci			goto error;
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_ci		argv[i] = cmdline + len;
256162306a36Sopenharmony_ci		memcpy(argv[i], str, strlen(str) + 1);
256262306a36Sopenharmony_ci		len += strlen(str) + 1;
256362306a36Sopenharmony_ci		free(str);
256462306a36Sopenharmony_ci	}
256562306a36Sopenharmony_ci	ff->ph->env.cmdline = cmdline;
256662306a36Sopenharmony_ci	ff->ph->env.cmdline_argv = (const char **) argv;
256762306a36Sopenharmony_ci	return 0;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_cierror:
257062306a36Sopenharmony_ci	free(argv);
257162306a36Sopenharmony_ci	free(cmdline);
257262306a36Sopenharmony_ci	return -1;
257362306a36Sopenharmony_ci}
257462306a36Sopenharmony_ci
257562306a36Sopenharmony_cistatic int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused)
257662306a36Sopenharmony_ci{
257762306a36Sopenharmony_ci	u32 nr, i;
257862306a36Sopenharmony_ci	char *str;
257962306a36Sopenharmony_ci	struct strbuf sb;
258062306a36Sopenharmony_ci	int cpu_nr = ff->ph->env.nr_cpus_avail;
258162306a36Sopenharmony_ci	u64 size = 0;
258262306a36Sopenharmony_ci	struct perf_header *ph = ff->ph;
258362306a36Sopenharmony_ci	bool do_core_id_test = true;
258462306a36Sopenharmony_ci
258562306a36Sopenharmony_ci	ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu));
258662306a36Sopenharmony_ci	if (!ph->env.cpu)
258762306a36Sopenharmony_ci		return -1;
258862306a36Sopenharmony_ci
258962306a36Sopenharmony_ci	if (do_read_u32(ff, &nr))
259062306a36Sopenharmony_ci		goto free_cpu;
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	ph->env.nr_sibling_cores = nr;
259362306a36Sopenharmony_ci	size += sizeof(u32);
259462306a36Sopenharmony_ci	if (strbuf_init(&sb, 128) < 0)
259562306a36Sopenharmony_ci		goto free_cpu;
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
259862306a36Sopenharmony_ci		str = do_read_string(ff);
259962306a36Sopenharmony_ci		if (!str)
260062306a36Sopenharmony_ci			goto error;
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci		/* include a NULL character at the end */
260362306a36Sopenharmony_ci		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
260462306a36Sopenharmony_ci			goto error;
260562306a36Sopenharmony_ci		size += string_size(str);
260662306a36Sopenharmony_ci		free(str);
260762306a36Sopenharmony_ci	}
260862306a36Sopenharmony_ci	ph->env.sibling_cores = strbuf_detach(&sb, NULL);
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci	if (do_read_u32(ff, &nr))
261162306a36Sopenharmony_ci		return -1;
261262306a36Sopenharmony_ci
261362306a36Sopenharmony_ci	ph->env.nr_sibling_threads = nr;
261462306a36Sopenharmony_ci	size += sizeof(u32);
261562306a36Sopenharmony_ci
261662306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
261762306a36Sopenharmony_ci		str = do_read_string(ff);
261862306a36Sopenharmony_ci		if (!str)
261962306a36Sopenharmony_ci			goto error;
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci		/* include a NULL character at the end */
262262306a36Sopenharmony_ci		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
262362306a36Sopenharmony_ci			goto error;
262462306a36Sopenharmony_ci		size += string_size(str);
262562306a36Sopenharmony_ci		free(str);
262662306a36Sopenharmony_ci	}
262762306a36Sopenharmony_ci	ph->env.sibling_threads = strbuf_detach(&sb, NULL);
262862306a36Sopenharmony_ci
262962306a36Sopenharmony_ci	/*
263062306a36Sopenharmony_ci	 * The header may be from old perf,
263162306a36Sopenharmony_ci	 * which doesn't include core id and socket id information.
263262306a36Sopenharmony_ci	 */
263362306a36Sopenharmony_ci	if (ff->size <= size) {
263462306a36Sopenharmony_ci		zfree(&ph->env.cpu);
263562306a36Sopenharmony_ci		return 0;
263662306a36Sopenharmony_ci	}
263762306a36Sopenharmony_ci
263862306a36Sopenharmony_ci	/* On s390 the socket_id number is not related to the numbers of cpus.
263962306a36Sopenharmony_ci	 * The socket_id number might be higher than the numbers of cpus.
264062306a36Sopenharmony_ci	 * This depends on the configuration.
264162306a36Sopenharmony_ci	 * AArch64 is the same.
264262306a36Sopenharmony_ci	 */
264362306a36Sopenharmony_ci	if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4)
264462306a36Sopenharmony_ci			  || !strncmp(ph->env.arch, "aarch64", 7)))
264562306a36Sopenharmony_ci		do_core_id_test = false;
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	for (i = 0; i < (u32)cpu_nr; i++) {
264862306a36Sopenharmony_ci		if (do_read_u32(ff, &nr))
264962306a36Sopenharmony_ci			goto free_cpu;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci		ph->env.cpu[i].core_id = nr;
265262306a36Sopenharmony_ci		size += sizeof(u32);
265362306a36Sopenharmony_ci
265462306a36Sopenharmony_ci		if (do_read_u32(ff, &nr))
265562306a36Sopenharmony_ci			goto free_cpu;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci		if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) {
265862306a36Sopenharmony_ci			pr_debug("socket_id number is too big."
265962306a36Sopenharmony_ci				 "You may need to upgrade the perf tool.\n");
266062306a36Sopenharmony_ci			goto free_cpu;
266162306a36Sopenharmony_ci		}
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci		ph->env.cpu[i].socket_id = nr;
266462306a36Sopenharmony_ci		size += sizeof(u32);
266562306a36Sopenharmony_ci	}
266662306a36Sopenharmony_ci
266762306a36Sopenharmony_ci	/*
266862306a36Sopenharmony_ci	 * The header may be from old perf,
266962306a36Sopenharmony_ci	 * which doesn't include die information.
267062306a36Sopenharmony_ci	 */
267162306a36Sopenharmony_ci	if (ff->size <= size)
267262306a36Sopenharmony_ci		return 0;
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci	if (do_read_u32(ff, &nr))
267562306a36Sopenharmony_ci		return -1;
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci	ph->env.nr_sibling_dies = nr;
267862306a36Sopenharmony_ci	size += sizeof(u32);
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
268162306a36Sopenharmony_ci		str = do_read_string(ff);
268262306a36Sopenharmony_ci		if (!str)
268362306a36Sopenharmony_ci			goto error;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_ci		/* include a NULL character at the end */
268662306a36Sopenharmony_ci		if (strbuf_add(&sb, str, strlen(str) + 1) < 0)
268762306a36Sopenharmony_ci			goto error;
268862306a36Sopenharmony_ci		size += string_size(str);
268962306a36Sopenharmony_ci		free(str);
269062306a36Sopenharmony_ci	}
269162306a36Sopenharmony_ci	ph->env.sibling_dies = strbuf_detach(&sb, NULL);
269262306a36Sopenharmony_ci
269362306a36Sopenharmony_ci	for (i = 0; i < (u32)cpu_nr; i++) {
269462306a36Sopenharmony_ci		if (do_read_u32(ff, &nr))
269562306a36Sopenharmony_ci			goto free_cpu;
269662306a36Sopenharmony_ci
269762306a36Sopenharmony_ci		ph->env.cpu[i].die_id = nr;
269862306a36Sopenharmony_ci	}
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	return 0;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_cierror:
270362306a36Sopenharmony_ci	strbuf_release(&sb);
270462306a36Sopenharmony_cifree_cpu:
270562306a36Sopenharmony_ci	zfree(&ph->env.cpu);
270662306a36Sopenharmony_ci	return -1;
270762306a36Sopenharmony_ci}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_cistatic int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused)
271062306a36Sopenharmony_ci{
271162306a36Sopenharmony_ci	struct numa_node *nodes, *n;
271262306a36Sopenharmony_ci	u32 nr, i;
271362306a36Sopenharmony_ci	char *str;
271462306a36Sopenharmony_ci
271562306a36Sopenharmony_ci	/* nr nodes */
271662306a36Sopenharmony_ci	if (do_read_u32(ff, &nr))
271762306a36Sopenharmony_ci		return -1;
271862306a36Sopenharmony_ci
271962306a36Sopenharmony_ci	nodes = zalloc(sizeof(*nodes) * nr);
272062306a36Sopenharmony_ci	if (!nodes)
272162306a36Sopenharmony_ci		return -ENOMEM;
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
272462306a36Sopenharmony_ci		n = &nodes[i];
272562306a36Sopenharmony_ci
272662306a36Sopenharmony_ci		/* node number */
272762306a36Sopenharmony_ci		if (do_read_u32(ff, &n->node))
272862306a36Sopenharmony_ci			goto error;
272962306a36Sopenharmony_ci
273062306a36Sopenharmony_ci		if (do_read_u64(ff, &n->mem_total))
273162306a36Sopenharmony_ci			goto error;
273262306a36Sopenharmony_ci
273362306a36Sopenharmony_ci		if (do_read_u64(ff, &n->mem_free))
273462306a36Sopenharmony_ci			goto error;
273562306a36Sopenharmony_ci
273662306a36Sopenharmony_ci		str = do_read_string(ff);
273762306a36Sopenharmony_ci		if (!str)
273862306a36Sopenharmony_ci			goto error;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci		n->map = perf_cpu_map__new(str);
274162306a36Sopenharmony_ci		if (!n->map)
274262306a36Sopenharmony_ci			goto error;
274362306a36Sopenharmony_ci
274462306a36Sopenharmony_ci		free(str);
274562306a36Sopenharmony_ci	}
274662306a36Sopenharmony_ci	ff->ph->env.nr_numa_nodes = nr;
274762306a36Sopenharmony_ci	ff->ph->env.numa_nodes = nodes;
274862306a36Sopenharmony_ci	return 0;
274962306a36Sopenharmony_ci
275062306a36Sopenharmony_cierror:
275162306a36Sopenharmony_ci	free(nodes);
275262306a36Sopenharmony_ci	return -1;
275362306a36Sopenharmony_ci}
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_cistatic int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused)
275662306a36Sopenharmony_ci{
275762306a36Sopenharmony_ci	char *name;
275862306a36Sopenharmony_ci	u32 pmu_num;
275962306a36Sopenharmony_ci	u32 type;
276062306a36Sopenharmony_ci	struct strbuf sb;
276162306a36Sopenharmony_ci
276262306a36Sopenharmony_ci	if (do_read_u32(ff, &pmu_num))
276362306a36Sopenharmony_ci		return -1;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	if (!pmu_num) {
276662306a36Sopenharmony_ci		pr_debug("pmu mappings not available\n");
276762306a36Sopenharmony_ci		return 0;
276862306a36Sopenharmony_ci	}
276962306a36Sopenharmony_ci
277062306a36Sopenharmony_ci	ff->ph->env.nr_pmu_mappings = pmu_num;
277162306a36Sopenharmony_ci	if (strbuf_init(&sb, 128) < 0)
277262306a36Sopenharmony_ci		return -1;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci	while (pmu_num) {
277562306a36Sopenharmony_ci		if (do_read_u32(ff, &type))
277662306a36Sopenharmony_ci			goto error;
277762306a36Sopenharmony_ci
277862306a36Sopenharmony_ci		name = do_read_string(ff);
277962306a36Sopenharmony_ci		if (!name)
278062306a36Sopenharmony_ci			goto error;
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci		if (strbuf_addf(&sb, "%u:%s", type, name) < 0)
278362306a36Sopenharmony_ci			goto error;
278462306a36Sopenharmony_ci		/* include a NULL character at the end */
278562306a36Sopenharmony_ci		if (strbuf_add(&sb, "", 1) < 0)
278662306a36Sopenharmony_ci			goto error;
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci		if (!strcmp(name, "msr"))
278962306a36Sopenharmony_ci			ff->ph->env.msr_pmu_type = type;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci		free(name);
279262306a36Sopenharmony_ci		pmu_num--;
279362306a36Sopenharmony_ci	}
279462306a36Sopenharmony_ci	ff->ph->env.pmu_mappings = strbuf_detach(&sb, NULL);
279562306a36Sopenharmony_ci	return 0;
279662306a36Sopenharmony_ci
279762306a36Sopenharmony_cierror:
279862306a36Sopenharmony_ci	strbuf_release(&sb);
279962306a36Sopenharmony_ci	return -1;
280062306a36Sopenharmony_ci}
280162306a36Sopenharmony_ci
280262306a36Sopenharmony_cistatic int process_group_desc(struct feat_fd *ff, void *data __maybe_unused)
280362306a36Sopenharmony_ci{
280462306a36Sopenharmony_ci	size_t ret = -1;
280562306a36Sopenharmony_ci	u32 i, nr, nr_groups;
280662306a36Sopenharmony_ci	struct perf_session *session;
280762306a36Sopenharmony_ci	struct evsel *evsel, *leader = NULL;
280862306a36Sopenharmony_ci	struct group_desc {
280962306a36Sopenharmony_ci		char *name;
281062306a36Sopenharmony_ci		u32 leader_idx;
281162306a36Sopenharmony_ci		u32 nr_members;
281262306a36Sopenharmony_ci	} *desc;
281362306a36Sopenharmony_ci
281462306a36Sopenharmony_ci	if (do_read_u32(ff, &nr_groups))
281562306a36Sopenharmony_ci		return -1;
281662306a36Sopenharmony_ci
281762306a36Sopenharmony_ci	ff->ph->env.nr_groups = nr_groups;
281862306a36Sopenharmony_ci	if (!nr_groups) {
281962306a36Sopenharmony_ci		pr_debug("group desc not available\n");
282062306a36Sopenharmony_ci		return 0;
282162306a36Sopenharmony_ci	}
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	desc = calloc(nr_groups, sizeof(*desc));
282462306a36Sopenharmony_ci	if (!desc)
282562306a36Sopenharmony_ci		return -1;
282662306a36Sopenharmony_ci
282762306a36Sopenharmony_ci	for (i = 0; i < nr_groups; i++) {
282862306a36Sopenharmony_ci		desc[i].name = do_read_string(ff);
282962306a36Sopenharmony_ci		if (!desc[i].name)
283062306a36Sopenharmony_ci			goto out_free;
283162306a36Sopenharmony_ci
283262306a36Sopenharmony_ci		if (do_read_u32(ff, &desc[i].leader_idx))
283362306a36Sopenharmony_ci			goto out_free;
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci		if (do_read_u32(ff, &desc[i].nr_members))
283662306a36Sopenharmony_ci			goto out_free;
283762306a36Sopenharmony_ci	}
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci	/*
284062306a36Sopenharmony_ci	 * Rebuild group relationship based on the group_desc
284162306a36Sopenharmony_ci	 */
284262306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	i = nr = 0;
284562306a36Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
284662306a36Sopenharmony_ci		if (i < nr_groups && evsel->core.idx == (int) desc[i].leader_idx) {
284762306a36Sopenharmony_ci			evsel__set_leader(evsel, evsel);
284862306a36Sopenharmony_ci			/* {anon_group} is a dummy name */
284962306a36Sopenharmony_ci			if (strcmp(desc[i].name, "{anon_group}")) {
285062306a36Sopenharmony_ci				evsel->group_name = desc[i].name;
285162306a36Sopenharmony_ci				desc[i].name = NULL;
285262306a36Sopenharmony_ci			}
285362306a36Sopenharmony_ci			evsel->core.nr_members = desc[i].nr_members;
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci			if (i >= nr_groups || nr > 0) {
285662306a36Sopenharmony_ci				pr_debug("invalid group desc\n");
285762306a36Sopenharmony_ci				goto out_free;
285862306a36Sopenharmony_ci			}
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci			leader = evsel;
286162306a36Sopenharmony_ci			nr = evsel->core.nr_members - 1;
286262306a36Sopenharmony_ci			i++;
286362306a36Sopenharmony_ci		} else if (nr) {
286462306a36Sopenharmony_ci			/* This is a group member */
286562306a36Sopenharmony_ci			evsel__set_leader(evsel, leader);
286662306a36Sopenharmony_ci
286762306a36Sopenharmony_ci			nr--;
286862306a36Sopenharmony_ci		}
286962306a36Sopenharmony_ci	}
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	if (i != nr_groups || nr != 0) {
287262306a36Sopenharmony_ci		pr_debug("invalid group desc\n");
287362306a36Sopenharmony_ci		goto out_free;
287462306a36Sopenharmony_ci	}
287562306a36Sopenharmony_ci
287662306a36Sopenharmony_ci	ret = 0;
287762306a36Sopenharmony_ciout_free:
287862306a36Sopenharmony_ci	for (i = 0; i < nr_groups; i++)
287962306a36Sopenharmony_ci		zfree(&desc[i].name);
288062306a36Sopenharmony_ci	free(desc);
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	return ret;
288362306a36Sopenharmony_ci}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_cistatic int process_auxtrace(struct feat_fd *ff, void *data __maybe_unused)
288662306a36Sopenharmony_ci{
288762306a36Sopenharmony_ci	struct perf_session *session;
288862306a36Sopenharmony_ci	int err;
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
289162306a36Sopenharmony_ci
289262306a36Sopenharmony_ci	err = auxtrace_index__process(ff->fd, ff->size, session,
289362306a36Sopenharmony_ci				      ff->ph->needs_swap);
289462306a36Sopenharmony_ci	if (err < 0)
289562306a36Sopenharmony_ci		pr_err("Failed to process auxtrace index\n");
289662306a36Sopenharmony_ci	return err;
289762306a36Sopenharmony_ci}
289862306a36Sopenharmony_ci
289962306a36Sopenharmony_cistatic int process_cache(struct feat_fd *ff, void *data __maybe_unused)
290062306a36Sopenharmony_ci{
290162306a36Sopenharmony_ci	struct cpu_cache_level *caches;
290262306a36Sopenharmony_ci	u32 cnt, i, version;
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	if (do_read_u32(ff, &version))
290562306a36Sopenharmony_ci		return -1;
290662306a36Sopenharmony_ci
290762306a36Sopenharmony_ci	if (version != 1)
290862306a36Sopenharmony_ci		return -1;
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci	if (do_read_u32(ff, &cnt))
291162306a36Sopenharmony_ci		return -1;
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	caches = zalloc(sizeof(*caches) * cnt);
291462306a36Sopenharmony_ci	if (!caches)
291562306a36Sopenharmony_ci		return -1;
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	for (i = 0; i < cnt; i++) {
291862306a36Sopenharmony_ci		struct cpu_cache_level c;
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci		#define _R(v)						\
292162306a36Sopenharmony_ci			if (do_read_u32(ff, &c.v))\
292262306a36Sopenharmony_ci				goto out_free_caches;			\
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci		_R(level)
292562306a36Sopenharmony_ci		_R(line_size)
292662306a36Sopenharmony_ci		_R(sets)
292762306a36Sopenharmony_ci		_R(ways)
292862306a36Sopenharmony_ci		#undef _R
292962306a36Sopenharmony_ci
293062306a36Sopenharmony_ci		#define _R(v)					\
293162306a36Sopenharmony_ci			c.v = do_read_string(ff);		\
293262306a36Sopenharmony_ci			if (!c.v)				\
293362306a36Sopenharmony_ci				goto out_free_caches;
293462306a36Sopenharmony_ci
293562306a36Sopenharmony_ci		_R(type)
293662306a36Sopenharmony_ci		_R(size)
293762306a36Sopenharmony_ci		_R(map)
293862306a36Sopenharmony_ci		#undef _R
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci		caches[i] = c;
294162306a36Sopenharmony_ci	}
294262306a36Sopenharmony_ci
294362306a36Sopenharmony_ci	ff->ph->env.caches = caches;
294462306a36Sopenharmony_ci	ff->ph->env.caches_cnt = cnt;
294562306a36Sopenharmony_ci	return 0;
294662306a36Sopenharmony_ciout_free_caches:
294762306a36Sopenharmony_ci	free(caches);
294862306a36Sopenharmony_ci	return -1;
294962306a36Sopenharmony_ci}
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_cistatic int process_sample_time(struct feat_fd *ff, void *data __maybe_unused)
295262306a36Sopenharmony_ci{
295362306a36Sopenharmony_ci	struct perf_session *session;
295462306a36Sopenharmony_ci	u64 first_sample_time, last_sample_time;
295562306a36Sopenharmony_ci	int ret;
295662306a36Sopenharmony_ci
295762306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
295862306a36Sopenharmony_ci
295962306a36Sopenharmony_ci	ret = do_read_u64(ff, &first_sample_time);
296062306a36Sopenharmony_ci	if (ret)
296162306a36Sopenharmony_ci		return -1;
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci	ret = do_read_u64(ff, &last_sample_time);
296462306a36Sopenharmony_ci	if (ret)
296562306a36Sopenharmony_ci		return -1;
296662306a36Sopenharmony_ci
296762306a36Sopenharmony_ci	session->evlist->first_sample_time = first_sample_time;
296862306a36Sopenharmony_ci	session->evlist->last_sample_time = last_sample_time;
296962306a36Sopenharmony_ci	return 0;
297062306a36Sopenharmony_ci}
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_cistatic int process_mem_topology(struct feat_fd *ff,
297362306a36Sopenharmony_ci				void *data __maybe_unused)
297462306a36Sopenharmony_ci{
297562306a36Sopenharmony_ci	struct memory_node *nodes;
297662306a36Sopenharmony_ci	u64 version, i, nr, bsize;
297762306a36Sopenharmony_ci	int ret = -1;
297862306a36Sopenharmony_ci
297962306a36Sopenharmony_ci	if (do_read_u64(ff, &version))
298062306a36Sopenharmony_ci		return -1;
298162306a36Sopenharmony_ci
298262306a36Sopenharmony_ci	if (version != 1)
298362306a36Sopenharmony_ci		return -1;
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	if (do_read_u64(ff, &bsize))
298662306a36Sopenharmony_ci		return -1;
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci	if (do_read_u64(ff, &nr))
298962306a36Sopenharmony_ci		return -1;
299062306a36Sopenharmony_ci
299162306a36Sopenharmony_ci	nodes = zalloc(sizeof(*nodes) * nr);
299262306a36Sopenharmony_ci	if (!nodes)
299362306a36Sopenharmony_ci		return -1;
299462306a36Sopenharmony_ci
299562306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
299662306a36Sopenharmony_ci		struct memory_node n;
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci		#define _R(v)				\
299962306a36Sopenharmony_ci			if (do_read_u64(ff, &n.v))	\
300062306a36Sopenharmony_ci				goto out;		\
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci		_R(node)
300362306a36Sopenharmony_ci		_R(size)
300462306a36Sopenharmony_ci
300562306a36Sopenharmony_ci		#undef _R
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci		if (do_read_bitmap(ff, &n.set, &n.size))
300862306a36Sopenharmony_ci			goto out;
300962306a36Sopenharmony_ci
301062306a36Sopenharmony_ci		nodes[i] = n;
301162306a36Sopenharmony_ci	}
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	ff->ph->env.memory_bsize    = bsize;
301462306a36Sopenharmony_ci	ff->ph->env.memory_nodes    = nodes;
301562306a36Sopenharmony_ci	ff->ph->env.nr_memory_nodes = nr;
301662306a36Sopenharmony_ci	ret = 0;
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ciout:
301962306a36Sopenharmony_ci	if (ret)
302062306a36Sopenharmony_ci		free(nodes);
302162306a36Sopenharmony_ci	return ret;
302262306a36Sopenharmony_ci}
302362306a36Sopenharmony_ci
302462306a36Sopenharmony_cistatic int process_clockid(struct feat_fd *ff,
302562306a36Sopenharmony_ci			   void *data __maybe_unused)
302662306a36Sopenharmony_ci{
302762306a36Sopenharmony_ci	if (do_read_u64(ff, &ff->ph->env.clock.clockid_res_ns))
302862306a36Sopenharmony_ci		return -1;
302962306a36Sopenharmony_ci
303062306a36Sopenharmony_ci	return 0;
303162306a36Sopenharmony_ci}
303262306a36Sopenharmony_ci
303362306a36Sopenharmony_cistatic int process_clock_data(struct feat_fd *ff,
303462306a36Sopenharmony_ci			      void *_data __maybe_unused)
303562306a36Sopenharmony_ci{
303662306a36Sopenharmony_ci	u32 data32;
303762306a36Sopenharmony_ci	u64 data64;
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci	/* version */
304062306a36Sopenharmony_ci	if (do_read_u32(ff, &data32))
304162306a36Sopenharmony_ci		return -1;
304262306a36Sopenharmony_ci
304362306a36Sopenharmony_ci	if (data32 != 1)
304462306a36Sopenharmony_ci		return -1;
304562306a36Sopenharmony_ci
304662306a36Sopenharmony_ci	/* clockid */
304762306a36Sopenharmony_ci	if (do_read_u32(ff, &data32))
304862306a36Sopenharmony_ci		return -1;
304962306a36Sopenharmony_ci
305062306a36Sopenharmony_ci	ff->ph->env.clock.clockid = data32;
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	/* TOD ref time */
305362306a36Sopenharmony_ci	if (do_read_u64(ff, &data64))
305462306a36Sopenharmony_ci		return -1;
305562306a36Sopenharmony_ci
305662306a36Sopenharmony_ci	ff->ph->env.clock.tod_ns = data64;
305762306a36Sopenharmony_ci
305862306a36Sopenharmony_ci	/* clockid ref time */
305962306a36Sopenharmony_ci	if (do_read_u64(ff, &data64))
306062306a36Sopenharmony_ci		return -1;
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	ff->ph->env.clock.clockid_ns = data64;
306362306a36Sopenharmony_ci	ff->ph->env.clock.enabled = true;
306462306a36Sopenharmony_ci	return 0;
306562306a36Sopenharmony_ci}
306662306a36Sopenharmony_ci
306762306a36Sopenharmony_cistatic int process_hybrid_topology(struct feat_fd *ff,
306862306a36Sopenharmony_ci				   void *data __maybe_unused)
306962306a36Sopenharmony_ci{
307062306a36Sopenharmony_ci	struct hybrid_node *nodes, *n;
307162306a36Sopenharmony_ci	u32 nr, i;
307262306a36Sopenharmony_ci
307362306a36Sopenharmony_ci	/* nr nodes */
307462306a36Sopenharmony_ci	if (do_read_u32(ff, &nr))
307562306a36Sopenharmony_ci		return -1;
307662306a36Sopenharmony_ci
307762306a36Sopenharmony_ci	nodes = zalloc(sizeof(*nodes) * nr);
307862306a36Sopenharmony_ci	if (!nodes)
307962306a36Sopenharmony_ci		return -ENOMEM;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
308262306a36Sopenharmony_ci		n = &nodes[i];
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_ci		n->pmu_name = do_read_string(ff);
308562306a36Sopenharmony_ci		if (!n->pmu_name)
308662306a36Sopenharmony_ci			goto error;
308762306a36Sopenharmony_ci
308862306a36Sopenharmony_ci		n->cpus = do_read_string(ff);
308962306a36Sopenharmony_ci		if (!n->cpus)
309062306a36Sopenharmony_ci			goto error;
309162306a36Sopenharmony_ci	}
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci	ff->ph->env.nr_hybrid_nodes = nr;
309462306a36Sopenharmony_ci	ff->ph->env.hybrid_nodes = nodes;
309562306a36Sopenharmony_ci	return 0;
309662306a36Sopenharmony_ci
309762306a36Sopenharmony_cierror:
309862306a36Sopenharmony_ci	for (i = 0; i < nr; i++) {
309962306a36Sopenharmony_ci		free(nodes[i].pmu_name);
310062306a36Sopenharmony_ci		free(nodes[i].cpus);
310162306a36Sopenharmony_ci	}
310262306a36Sopenharmony_ci
310362306a36Sopenharmony_ci	free(nodes);
310462306a36Sopenharmony_ci	return -1;
310562306a36Sopenharmony_ci}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_cistatic int process_dir_format(struct feat_fd *ff,
310862306a36Sopenharmony_ci			      void *_data __maybe_unused)
310962306a36Sopenharmony_ci{
311062306a36Sopenharmony_ci	struct perf_session *session;
311162306a36Sopenharmony_ci	struct perf_data *data;
311262306a36Sopenharmony_ci
311362306a36Sopenharmony_ci	session = container_of(ff->ph, struct perf_session, header);
311462306a36Sopenharmony_ci	data = session->data;
311562306a36Sopenharmony_ci
311662306a36Sopenharmony_ci	if (WARN_ON(!perf_data__is_dir(data)))
311762306a36Sopenharmony_ci		return -1;
311862306a36Sopenharmony_ci
311962306a36Sopenharmony_ci	return do_read_u64(ff, &data->dir.version);
312062306a36Sopenharmony_ci}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
312362306a36Sopenharmony_cistatic int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused)
312462306a36Sopenharmony_ci{
312562306a36Sopenharmony_ci	struct bpf_prog_info_node *info_node;
312662306a36Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
312762306a36Sopenharmony_ci	struct perf_bpil *info_linear;
312862306a36Sopenharmony_ci	u32 count, i;
312962306a36Sopenharmony_ci	int err = -1;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	if (ff->ph->needs_swap) {
313262306a36Sopenharmony_ci		pr_warning("interpreting bpf_prog_info from systems with endianness is not yet supported\n");
313362306a36Sopenharmony_ci		return 0;
313462306a36Sopenharmony_ci	}
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci	if (do_read_u32(ff, &count))
313762306a36Sopenharmony_ci		return -1;
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	down_write(&env->bpf_progs.lock);
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
314262306a36Sopenharmony_ci		u32 info_len, data_len;
314362306a36Sopenharmony_ci
314462306a36Sopenharmony_ci		info_linear = NULL;
314562306a36Sopenharmony_ci		info_node = NULL;
314662306a36Sopenharmony_ci		if (do_read_u32(ff, &info_len))
314762306a36Sopenharmony_ci			goto out;
314862306a36Sopenharmony_ci		if (do_read_u32(ff, &data_len))
314962306a36Sopenharmony_ci			goto out;
315062306a36Sopenharmony_ci
315162306a36Sopenharmony_ci		if (info_len > sizeof(struct bpf_prog_info)) {
315262306a36Sopenharmony_ci			pr_warning("detected invalid bpf_prog_info\n");
315362306a36Sopenharmony_ci			goto out;
315462306a36Sopenharmony_ci		}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci		info_linear = malloc(sizeof(struct perf_bpil) +
315762306a36Sopenharmony_ci				     data_len);
315862306a36Sopenharmony_ci		if (!info_linear)
315962306a36Sopenharmony_ci			goto out;
316062306a36Sopenharmony_ci		info_linear->info_len = sizeof(struct bpf_prog_info);
316162306a36Sopenharmony_ci		info_linear->data_len = data_len;
316262306a36Sopenharmony_ci		if (do_read_u64(ff, (u64 *)(&info_linear->arrays)))
316362306a36Sopenharmony_ci			goto out;
316462306a36Sopenharmony_ci		if (__do_read(ff, &info_linear->info, info_len))
316562306a36Sopenharmony_ci			goto out;
316662306a36Sopenharmony_ci		if (info_len < sizeof(struct bpf_prog_info))
316762306a36Sopenharmony_ci			memset(((void *)(&info_linear->info)) + info_len, 0,
316862306a36Sopenharmony_ci			       sizeof(struct bpf_prog_info) - info_len);
316962306a36Sopenharmony_ci
317062306a36Sopenharmony_ci		if (__do_read(ff, info_linear->data, data_len))
317162306a36Sopenharmony_ci			goto out;
317262306a36Sopenharmony_ci
317362306a36Sopenharmony_ci		info_node = malloc(sizeof(struct bpf_prog_info_node));
317462306a36Sopenharmony_ci		if (!info_node)
317562306a36Sopenharmony_ci			goto out;
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci		/* after reading from file, translate offset to address */
317862306a36Sopenharmony_ci		bpil_offs_to_addr(info_linear);
317962306a36Sopenharmony_ci		info_node->info_linear = info_linear;
318062306a36Sopenharmony_ci		__perf_env__insert_bpf_prog_info(env, info_node);
318162306a36Sopenharmony_ci	}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	up_write(&env->bpf_progs.lock);
318462306a36Sopenharmony_ci	return 0;
318562306a36Sopenharmony_ciout:
318662306a36Sopenharmony_ci	free(info_linear);
318762306a36Sopenharmony_ci	free(info_node);
318862306a36Sopenharmony_ci	up_write(&env->bpf_progs.lock);
318962306a36Sopenharmony_ci	return err;
319062306a36Sopenharmony_ci}
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_cistatic int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused)
319362306a36Sopenharmony_ci{
319462306a36Sopenharmony_ci	struct perf_env *env = &ff->ph->env;
319562306a36Sopenharmony_ci	struct btf_node *node = NULL;
319662306a36Sopenharmony_ci	u32 count, i;
319762306a36Sopenharmony_ci	int err = -1;
319862306a36Sopenharmony_ci
319962306a36Sopenharmony_ci	if (ff->ph->needs_swap) {
320062306a36Sopenharmony_ci		pr_warning("interpreting btf from systems with endianness is not yet supported\n");
320162306a36Sopenharmony_ci		return 0;
320262306a36Sopenharmony_ci	}
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	if (do_read_u32(ff, &count))
320562306a36Sopenharmony_ci		return -1;
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	down_write(&env->bpf_progs.lock);
320862306a36Sopenharmony_ci
320962306a36Sopenharmony_ci	for (i = 0; i < count; ++i) {
321062306a36Sopenharmony_ci		u32 id, data_size;
321162306a36Sopenharmony_ci
321262306a36Sopenharmony_ci		if (do_read_u32(ff, &id))
321362306a36Sopenharmony_ci			goto out;
321462306a36Sopenharmony_ci		if (do_read_u32(ff, &data_size))
321562306a36Sopenharmony_ci			goto out;
321662306a36Sopenharmony_ci
321762306a36Sopenharmony_ci		node = malloc(sizeof(struct btf_node) + data_size);
321862306a36Sopenharmony_ci		if (!node)
321962306a36Sopenharmony_ci			goto out;
322062306a36Sopenharmony_ci
322162306a36Sopenharmony_ci		node->id = id;
322262306a36Sopenharmony_ci		node->data_size = data_size;
322362306a36Sopenharmony_ci
322462306a36Sopenharmony_ci		if (__do_read(ff, node->data, data_size))
322562306a36Sopenharmony_ci			goto out;
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci		__perf_env__insert_btf(env, node);
322862306a36Sopenharmony_ci		node = NULL;
322962306a36Sopenharmony_ci	}
323062306a36Sopenharmony_ci
323162306a36Sopenharmony_ci	err = 0;
323262306a36Sopenharmony_ciout:
323362306a36Sopenharmony_ci	up_write(&env->bpf_progs.lock);
323462306a36Sopenharmony_ci	free(node);
323562306a36Sopenharmony_ci	return err;
323662306a36Sopenharmony_ci}
323762306a36Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT
323862306a36Sopenharmony_ci
323962306a36Sopenharmony_cistatic int process_compressed(struct feat_fd *ff,
324062306a36Sopenharmony_ci			      void *data __maybe_unused)
324162306a36Sopenharmony_ci{
324262306a36Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_ver)))
324362306a36Sopenharmony_ci		return -1;
324462306a36Sopenharmony_ci
324562306a36Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_type)))
324662306a36Sopenharmony_ci		return -1;
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_level)))
324962306a36Sopenharmony_ci		return -1;
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_ratio)))
325262306a36Sopenharmony_ci		return -1;
325362306a36Sopenharmony_ci
325462306a36Sopenharmony_ci	if (do_read_u32(ff, &(ff->ph->env.comp_mmap_len)))
325562306a36Sopenharmony_ci		return -1;
325662306a36Sopenharmony_ci
325762306a36Sopenharmony_ci	return 0;
325862306a36Sopenharmony_ci}
325962306a36Sopenharmony_ci
326062306a36Sopenharmony_cistatic int __process_pmu_caps(struct feat_fd *ff, int *nr_caps,
326162306a36Sopenharmony_ci			      char ***caps, unsigned int *max_branches)
326262306a36Sopenharmony_ci{
326362306a36Sopenharmony_ci	char *name, *value, *ptr;
326462306a36Sopenharmony_ci	u32 nr_pmu_caps, i;
326562306a36Sopenharmony_ci
326662306a36Sopenharmony_ci	*nr_caps = 0;
326762306a36Sopenharmony_ci	*caps = NULL;
326862306a36Sopenharmony_ci
326962306a36Sopenharmony_ci	if (do_read_u32(ff, &nr_pmu_caps))
327062306a36Sopenharmony_ci		return -1;
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_ci	if (!nr_pmu_caps)
327362306a36Sopenharmony_ci		return 0;
327462306a36Sopenharmony_ci
327562306a36Sopenharmony_ci	*caps = zalloc(sizeof(char *) * nr_pmu_caps);
327662306a36Sopenharmony_ci	if (!*caps)
327762306a36Sopenharmony_ci		return -1;
327862306a36Sopenharmony_ci
327962306a36Sopenharmony_ci	for (i = 0; i < nr_pmu_caps; i++) {
328062306a36Sopenharmony_ci		name = do_read_string(ff);
328162306a36Sopenharmony_ci		if (!name)
328262306a36Sopenharmony_ci			goto error;
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci		value = do_read_string(ff);
328562306a36Sopenharmony_ci		if (!value)
328662306a36Sopenharmony_ci			goto free_name;
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci		if (asprintf(&ptr, "%s=%s", name, value) < 0)
328962306a36Sopenharmony_ci			goto free_value;
329062306a36Sopenharmony_ci
329162306a36Sopenharmony_ci		(*caps)[i] = ptr;
329262306a36Sopenharmony_ci
329362306a36Sopenharmony_ci		if (!strcmp(name, "branches"))
329462306a36Sopenharmony_ci			*max_branches = atoi(value);
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci		free(value);
329762306a36Sopenharmony_ci		free(name);
329862306a36Sopenharmony_ci	}
329962306a36Sopenharmony_ci	*nr_caps = nr_pmu_caps;
330062306a36Sopenharmony_ci	return 0;
330162306a36Sopenharmony_ci
330262306a36Sopenharmony_cifree_value:
330362306a36Sopenharmony_ci	free(value);
330462306a36Sopenharmony_cifree_name:
330562306a36Sopenharmony_ci	free(name);
330662306a36Sopenharmony_cierror:
330762306a36Sopenharmony_ci	for (; i > 0; i--)
330862306a36Sopenharmony_ci		free((*caps)[i - 1]);
330962306a36Sopenharmony_ci	free(*caps);
331062306a36Sopenharmony_ci	*caps = NULL;
331162306a36Sopenharmony_ci	*nr_caps = 0;
331262306a36Sopenharmony_ci	return -1;
331362306a36Sopenharmony_ci}
331462306a36Sopenharmony_ci
331562306a36Sopenharmony_cistatic int process_cpu_pmu_caps(struct feat_fd *ff,
331662306a36Sopenharmony_ci				void *data __maybe_unused)
331762306a36Sopenharmony_ci{
331862306a36Sopenharmony_ci	int ret = __process_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps,
331962306a36Sopenharmony_ci				     &ff->ph->env.cpu_pmu_caps,
332062306a36Sopenharmony_ci				     &ff->ph->env.max_branches);
332162306a36Sopenharmony_ci
332262306a36Sopenharmony_ci	if (!ret && !ff->ph->env.cpu_pmu_caps)
332362306a36Sopenharmony_ci		pr_debug("cpu pmu capabilities not available\n");
332462306a36Sopenharmony_ci	return ret;
332562306a36Sopenharmony_ci}
332662306a36Sopenharmony_ci
332762306a36Sopenharmony_cistatic int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused)
332862306a36Sopenharmony_ci{
332962306a36Sopenharmony_ci	struct pmu_caps *pmu_caps;
333062306a36Sopenharmony_ci	u32 nr_pmu, i;
333162306a36Sopenharmony_ci	int ret;
333262306a36Sopenharmony_ci	int j;
333362306a36Sopenharmony_ci
333462306a36Sopenharmony_ci	if (do_read_u32(ff, &nr_pmu))
333562306a36Sopenharmony_ci		return -1;
333662306a36Sopenharmony_ci
333762306a36Sopenharmony_ci	if (!nr_pmu) {
333862306a36Sopenharmony_ci		pr_debug("pmu capabilities not available\n");
333962306a36Sopenharmony_ci		return 0;
334062306a36Sopenharmony_ci	}
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	pmu_caps = zalloc(sizeof(*pmu_caps) * nr_pmu);
334362306a36Sopenharmony_ci	if (!pmu_caps)
334462306a36Sopenharmony_ci		return -ENOMEM;
334562306a36Sopenharmony_ci
334662306a36Sopenharmony_ci	for (i = 0; i < nr_pmu; i++) {
334762306a36Sopenharmony_ci		ret = __process_pmu_caps(ff, &pmu_caps[i].nr_caps,
334862306a36Sopenharmony_ci					 &pmu_caps[i].caps,
334962306a36Sopenharmony_ci					 &pmu_caps[i].max_branches);
335062306a36Sopenharmony_ci		if (ret)
335162306a36Sopenharmony_ci			goto err;
335262306a36Sopenharmony_ci
335362306a36Sopenharmony_ci		pmu_caps[i].pmu_name = do_read_string(ff);
335462306a36Sopenharmony_ci		if (!pmu_caps[i].pmu_name) {
335562306a36Sopenharmony_ci			ret = -1;
335662306a36Sopenharmony_ci			goto err;
335762306a36Sopenharmony_ci		}
335862306a36Sopenharmony_ci		if (!pmu_caps[i].nr_caps) {
335962306a36Sopenharmony_ci			pr_debug("%s pmu capabilities not available\n",
336062306a36Sopenharmony_ci				 pmu_caps[i].pmu_name);
336162306a36Sopenharmony_ci		}
336262306a36Sopenharmony_ci	}
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci	ff->ph->env.nr_pmus_with_caps = nr_pmu;
336562306a36Sopenharmony_ci	ff->ph->env.pmu_caps = pmu_caps;
336662306a36Sopenharmony_ci	return 0;
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_cierr:
336962306a36Sopenharmony_ci	for (i = 0; i < nr_pmu; i++) {
337062306a36Sopenharmony_ci		for (j = 0; j < pmu_caps[i].nr_caps; j++)
337162306a36Sopenharmony_ci			free(pmu_caps[i].caps[j]);
337262306a36Sopenharmony_ci		free(pmu_caps[i].caps);
337362306a36Sopenharmony_ci		free(pmu_caps[i].pmu_name);
337462306a36Sopenharmony_ci	}
337562306a36Sopenharmony_ci
337662306a36Sopenharmony_ci	free(pmu_caps);
337762306a36Sopenharmony_ci	return ret;
337862306a36Sopenharmony_ci}
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci#define FEAT_OPR(n, func, __full_only) \
338162306a36Sopenharmony_ci	[HEADER_##n] = {					\
338262306a36Sopenharmony_ci		.name	    = __stringify(n),			\
338362306a36Sopenharmony_ci		.write	    = write_##func,			\
338462306a36Sopenharmony_ci		.print	    = print_##func,			\
338562306a36Sopenharmony_ci		.full_only  = __full_only,			\
338662306a36Sopenharmony_ci		.process    = process_##func,			\
338762306a36Sopenharmony_ci		.synthesize = true				\
338862306a36Sopenharmony_ci	}
338962306a36Sopenharmony_ci
339062306a36Sopenharmony_ci#define FEAT_OPN(n, func, __full_only) \
339162306a36Sopenharmony_ci	[HEADER_##n] = {					\
339262306a36Sopenharmony_ci		.name	    = __stringify(n),			\
339362306a36Sopenharmony_ci		.write	    = write_##func,			\
339462306a36Sopenharmony_ci		.print	    = print_##func,			\
339562306a36Sopenharmony_ci		.full_only  = __full_only,			\
339662306a36Sopenharmony_ci		.process    = process_##func			\
339762306a36Sopenharmony_ci	}
339862306a36Sopenharmony_ci
339962306a36Sopenharmony_ci/* feature_ops not implemented: */
340062306a36Sopenharmony_ci#define print_tracing_data	NULL
340162306a36Sopenharmony_ci#define print_build_id		NULL
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci#define process_branch_stack	NULL
340462306a36Sopenharmony_ci#define process_stat		NULL
340562306a36Sopenharmony_ci
340662306a36Sopenharmony_ci// Only used in util/synthetic-events.c
340762306a36Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE];
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
341062306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
341162306a36Sopenharmony_ci	FEAT_OPN(TRACING_DATA,	tracing_data,	false),
341262306a36Sopenharmony_ci#endif
341362306a36Sopenharmony_ci	FEAT_OPN(BUILD_ID,	build_id,	false),
341462306a36Sopenharmony_ci	FEAT_OPR(HOSTNAME,	hostname,	false),
341562306a36Sopenharmony_ci	FEAT_OPR(OSRELEASE,	osrelease,	false),
341662306a36Sopenharmony_ci	FEAT_OPR(VERSION,	version,	false),
341762306a36Sopenharmony_ci	FEAT_OPR(ARCH,		arch,		false),
341862306a36Sopenharmony_ci	FEAT_OPR(NRCPUS,	nrcpus,		false),
341962306a36Sopenharmony_ci	FEAT_OPR(CPUDESC,	cpudesc,	false),
342062306a36Sopenharmony_ci	FEAT_OPR(CPUID,		cpuid,		false),
342162306a36Sopenharmony_ci	FEAT_OPR(TOTAL_MEM,	total_mem,	false),
342262306a36Sopenharmony_ci	FEAT_OPR(EVENT_DESC,	event_desc,	false),
342362306a36Sopenharmony_ci	FEAT_OPR(CMDLINE,	cmdline,	false),
342462306a36Sopenharmony_ci	FEAT_OPR(CPU_TOPOLOGY,	cpu_topology,	true),
342562306a36Sopenharmony_ci	FEAT_OPR(NUMA_TOPOLOGY,	numa_topology,	true),
342662306a36Sopenharmony_ci	FEAT_OPN(BRANCH_STACK,	branch_stack,	false),
342762306a36Sopenharmony_ci	FEAT_OPR(PMU_MAPPINGS,	pmu_mappings,	false),
342862306a36Sopenharmony_ci	FEAT_OPR(GROUP_DESC,	group_desc,	false),
342962306a36Sopenharmony_ci	FEAT_OPN(AUXTRACE,	auxtrace,	false),
343062306a36Sopenharmony_ci	FEAT_OPN(STAT,		stat,		false),
343162306a36Sopenharmony_ci	FEAT_OPN(CACHE,		cache,		true),
343262306a36Sopenharmony_ci	FEAT_OPR(SAMPLE_TIME,	sample_time,	false),
343362306a36Sopenharmony_ci	FEAT_OPR(MEM_TOPOLOGY,	mem_topology,	true),
343462306a36Sopenharmony_ci	FEAT_OPR(CLOCKID,	clockid,	false),
343562306a36Sopenharmony_ci	FEAT_OPN(DIR_FORMAT,	dir_format,	false),
343662306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT
343762306a36Sopenharmony_ci	FEAT_OPR(BPF_PROG_INFO, bpf_prog_info,  false),
343862306a36Sopenharmony_ci	FEAT_OPR(BPF_BTF,       bpf_btf,        false),
343962306a36Sopenharmony_ci#endif
344062306a36Sopenharmony_ci	FEAT_OPR(COMPRESSED,	compressed,	false),
344162306a36Sopenharmony_ci	FEAT_OPR(CPU_PMU_CAPS,	cpu_pmu_caps,	false),
344262306a36Sopenharmony_ci	FEAT_OPR(CLOCK_DATA,	clock_data,	false),
344362306a36Sopenharmony_ci	FEAT_OPN(HYBRID_TOPOLOGY,	hybrid_topology,	true),
344462306a36Sopenharmony_ci	FEAT_OPR(PMU_CAPS,	pmu_caps,	false),
344562306a36Sopenharmony_ci};
344662306a36Sopenharmony_ci
344762306a36Sopenharmony_cistruct header_print_data {
344862306a36Sopenharmony_ci	FILE *fp;
344962306a36Sopenharmony_ci	bool full; /* extended list of headers */
345062306a36Sopenharmony_ci};
345162306a36Sopenharmony_ci
345262306a36Sopenharmony_cistatic int perf_file_section__fprintf_info(struct perf_file_section *section,
345362306a36Sopenharmony_ci					   struct perf_header *ph,
345462306a36Sopenharmony_ci					   int feat, int fd, void *data)
345562306a36Sopenharmony_ci{
345662306a36Sopenharmony_ci	struct header_print_data *hd = data;
345762306a36Sopenharmony_ci	struct feat_fd ff;
345862306a36Sopenharmony_ci
345962306a36Sopenharmony_ci	if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
346062306a36Sopenharmony_ci		pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
346162306a36Sopenharmony_ci				"%d, continuing...\n", section->offset, feat);
346262306a36Sopenharmony_ci		return 0;
346362306a36Sopenharmony_ci	}
346462306a36Sopenharmony_ci	if (feat >= HEADER_LAST_FEATURE) {
346562306a36Sopenharmony_ci		pr_warning("unknown feature %d\n", feat);
346662306a36Sopenharmony_ci		return 0;
346762306a36Sopenharmony_ci	}
346862306a36Sopenharmony_ci	if (!feat_ops[feat].print)
346962306a36Sopenharmony_ci		return 0;
347062306a36Sopenharmony_ci
347162306a36Sopenharmony_ci	ff = (struct  feat_fd) {
347262306a36Sopenharmony_ci		.fd = fd,
347362306a36Sopenharmony_ci		.ph = ph,
347462306a36Sopenharmony_ci	};
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	if (!feat_ops[feat].full_only || hd->full)
347762306a36Sopenharmony_ci		feat_ops[feat].print(&ff, hd->fp);
347862306a36Sopenharmony_ci	else
347962306a36Sopenharmony_ci		fprintf(hd->fp, "# %s info available, use -I to display\n",
348062306a36Sopenharmony_ci			feat_ops[feat].name);
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	return 0;
348362306a36Sopenharmony_ci}
348462306a36Sopenharmony_ci
348562306a36Sopenharmony_ciint perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full)
348662306a36Sopenharmony_ci{
348762306a36Sopenharmony_ci	struct header_print_data hd;
348862306a36Sopenharmony_ci	struct perf_header *header = &session->header;
348962306a36Sopenharmony_ci	int fd = perf_data__fd(session->data);
349062306a36Sopenharmony_ci	struct stat st;
349162306a36Sopenharmony_ci	time_t stctime;
349262306a36Sopenharmony_ci	int ret, bit;
349362306a36Sopenharmony_ci
349462306a36Sopenharmony_ci	hd.fp = fp;
349562306a36Sopenharmony_ci	hd.full = full;
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci	ret = fstat(fd, &st);
349862306a36Sopenharmony_ci	if (ret == -1)
349962306a36Sopenharmony_ci		return -1;
350062306a36Sopenharmony_ci
350162306a36Sopenharmony_ci	stctime = st.st_mtime;
350262306a36Sopenharmony_ci	fprintf(fp, "# captured on    : %s", ctime(&stctime));
350362306a36Sopenharmony_ci
350462306a36Sopenharmony_ci	fprintf(fp, "# header version : %u\n", header->version);
350562306a36Sopenharmony_ci	fprintf(fp, "# data offset    : %" PRIu64 "\n", header->data_offset);
350662306a36Sopenharmony_ci	fprintf(fp, "# data size      : %" PRIu64 "\n", header->data_size);
350762306a36Sopenharmony_ci	fprintf(fp, "# feat offset    : %" PRIu64 "\n", header->feat_offset);
350862306a36Sopenharmony_ci
350962306a36Sopenharmony_ci	perf_header__process_sections(header, fd, &hd,
351062306a36Sopenharmony_ci				      perf_file_section__fprintf_info);
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci	if (session->data->is_pipe)
351362306a36Sopenharmony_ci		return 0;
351462306a36Sopenharmony_ci
351562306a36Sopenharmony_ci	fprintf(fp, "# missing features: ");
351662306a36Sopenharmony_ci	for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) {
351762306a36Sopenharmony_ci		if (bit)
351862306a36Sopenharmony_ci			fprintf(fp, "%s ", feat_ops[bit].name);
351962306a36Sopenharmony_ci	}
352062306a36Sopenharmony_ci
352162306a36Sopenharmony_ci	fprintf(fp, "\n");
352262306a36Sopenharmony_ci	return 0;
352362306a36Sopenharmony_ci}
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_cistruct header_fw {
352662306a36Sopenharmony_ci	struct feat_writer	fw;
352762306a36Sopenharmony_ci	struct feat_fd		*ff;
352862306a36Sopenharmony_ci};
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_cistatic int feat_writer_cb(struct feat_writer *fw, void *buf, size_t sz)
353162306a36Sopenharmony_ci{
353262306a36Sopenharmony_ci	struct header_fw *h = container_of(fw, struct header_fw, fw);
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci	return do_write(h->ff, buf, sz);
353562306a36Sopenharmony_ci}
353662306a36Sopenharmony_ci
353762306a36Sopenharmony_cistatic int do_write_feat(struct feat_fd *ff, int type,
353862306a36Sopenharmony_ci			 struct perf_file_section **p,
353962306a36Sopenharmony_ci			 struct evlist *evlist,
354062306a36Sopenharmony_ci			 struct feat_copier *fc)
354162306a36Sopenharmony_ci{
354262306a36Sopenharmony_ci	int err;
354362306a36Sopenharmony_ci	int ret = 0;
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	if (perf_header__has_feat(ff->ph, type)) {
354662306a36Sopenharmony_ci		if (!feat_ops[type].write)
354762306a36Sopenharmony_ci			return -1;
354862306a36Sopenharmony_ci
354962306a36Sopenharmony_ci		if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__))
355062306a36Sopenharmony_ci			return -1;
355162306a36Sopenharmony_ci
355262306a36Sopenharmony_ci		(*p)->offset = lseek(ff->fd, 0, SEEK_CUR);
355362306a36Sopenharmony_ci
355462306a36Sopenharmony_ci		/*
355562306a36Sopenharmony_ci		 * Hook to let perf inject copy features sections from the input
355662306a36Sopenharmony_ci		 * file.
355762306a36Sopenharmony_ci		 */
355862306a36Sopenharmony_ci		if (fc && fc->copy) {
355962306a36Sopenharmony_ci			struct header_fw h = {
356062306a36Sopenharmony_ci				.fw.write = feat_writer_cb,
356162306a36Sopenharmony_ci				.ff = ff,
356262306a36Sopenharmony_ci			};
356362306a36Sopenharmony_ci
356462306a36Sopenharmony_ci			/* ->copy() returns 0 if the feature was not copied */
356562306a36Sopenharmony_ci			err = fc->copy(fc, type, &h.fw);
356662306a36Sopenharmony_ci		} else {
356762306a36Sopenharmony_ci			err = 0;
356862306a36Sopenharmony_ci		}
356962306a36Sopenharmony_ci		if (!err)
357062306a36Sopenharmony_ci			err = feat_ops[type].write(ff, evlist);
357162306a36Sopenharmony_ci		if (err < 0) {
357262306a36Sopenharmony_ci			pr_debug("failed to write feature %s\n", feat_ops[type].name);
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci			/* undo anything written */
357562306a36Sopenharmony_ci			lseek(ff->fd, (*p)->offset, SEEK_SET);
357662306a36Sopenharmony_ci
357762306a36Sopenharmony_ci			return -1;
357862306a36Sopenharmony_ci		}
357962306a36Sopenharmony_ci		(*p)->size = lseek(ff->fd, 0, SEEK_CUR) - (*p)->offset;
358062306a36Sopenharmony_ci		(*p)++;
358162306a36Sopenharmony_ci	}
358262306a36Sopenharmony_ci	return ret;
358362306a36Sopenharmony_ci}
358462306a36Sopenharmony_ci
358562306a36Sopenharmony_cistatic int perf_header__adds_write(struct perf_header *header,
358662306a36Sopenharmony_ci				   struct evlist *evlist, int fd,
358762306a36Sopenharmony_ci				   struct feat_copier *fc)
358862306a36Sopenharmony_ci{
358962306a36Sopenharmony_ci	int nr_sections;
359062306a36Sopenharmony_ci	struct feat_fd ff;
359162306a36Sopenharmony_ci	struct perf_file_section *feat_sec, *p;
359262306a36Sopenharmony_ci	int sec_size;
359362306a36Sopenharmony_ci	u64 sec_start;
359462306a36Sopenharmony_ci	int feat;
359562306a36Sopenharmony_ci	int err;
359662306a36Sopenharmony_ci
359762306a36Sopenharmony_ci	ff = (struct feat_fd){
359862306a36Sopenharmony_ci		.fd  = fd,
359962306a36Sopenharmony_ci		.ph = header,
360062306a36Sopenharmony_ci	};
360162306a36Sopenharmony_ci
360262306a36Sopenharmony_ci	nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
360362306a36Sopenharmony_ci	if (!nr_sections)
360462306a36Sopenharmony_ci		return 0;
360562306a36Sopenharmony_ci
360662306a36Sopenharmony_ci	feat_sec = p = calloc(nr_sections, sizeof(*feat_sec));
360762306a36Sopenharmony_ci	if (feat_sec == NULL)
360862306a36Sopenharmony_ci		return -ENOMEM;
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	sec_size = sizeof(*feat_sec) * nr_sections;
361162306a36Sopenharmony_ci
361262306a36Sopenharmony_ci	sec_start = header->feat_offset;
361362306a36Sopenharmony_ci	lseek(fd, sec_start + sec_size, SEEK_SET);
361462306a36Sopenharmony_ci
361562306a36Sopenharmony_ci	for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) {
361662306a36Sopenharmony_ci		if (do_write_feat(&ff, feat, &p, evlist, fc))
361762306a36Sopenharmony_ci			perf_header__clear_feat(header, feat);
361862306a36Sopenharmony_ci	}
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci	lseek(fd, sec_start, SEEK_SET);
362162306a36Sopenharmony_ci	/*
362262306a36Sopenharmony_ci	 * may write more than needed due to dropped feature, but
362362306a36Sopenharmony_ci	 * this is okay, reader will skip the missing entries
362462306a36Sopenharmony_ci	 */
362562306a36Sopenharmony_ci	err = do_write(&ff, feat_sec, sec_size);
362662306a36Sopenharmony_ci	if (err < 0)
362762306a36Sopenharmony_ci		pr_debug("failed to write feature section\n");
362862306a36Sopenharmony_ci	free(feat_sec);
362962306a36Sopenharmony_ci	return err;
363062306a36Sopenharmony_ci}
363162306a36Sopenharmony_ci
363262306a36Sopenharmony_ciint perf_header__write_pipe(int fd)
363362306a36Sopenharmony_ci{
363462306a36Sopenharmony_ci	struct perf_pipe_file_header f_header;
363562306a36Sopenharmony_ci	struct feat_fd ff;
363662306a36Sopenharmony_ci	int err;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	ff = (struct feat_fd){ .fd = fd };
363962306a36Sopenharmony_ci
364062306a36Sopenharmony_ci	f_header = (struct perf_pipe_file_header){
364162306a36Sopenharmony_ci		.magic	   = PERF_MAGIC,
364262306a36Sopenharmony_ci		.size	   = sizeof(f_header),
364362306a36Sopenharmony_ci	};
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci	err = do_write(&ff, &f_header, sizeof(f_header));
364662306a36Sopenharmony_ci	if (err < 0) {
364762306a36Sopenharmony_ci		pr_debug("failed to write perf pipe header\n");
364862306a36Sopenharmony_ci		return err;
364962306a36Sopenharmony_ci	}
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci	return 0;
365262306a36Sopenharmony_ci}
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_cistatic int perf_session__do_write_header(struct perf_session *session,
365562306a36Sopenharmony_ci					 struct evlist *evlist,
365662306a36Sopenharmony_ci					 int fd, bool at_exit,
365762306a36Sopenharmony_ci					 struct feat_copier *fc)
365862306a36Sopenharmony_ci{
365962306a36Sopenharmony_ci	struct perf_file_header f_header;
366062306a36Sopenharmony_ci	struct perf_file_attr   f_attr;
366162306a36Sopenharmony_ci	struct perf_header *header = &session->header;
366262306a36Sopenharmony_ci	struct evsel *evsel;
366362306a36Sopenharmony_ci	struct feat_fd ff;
366462306a36Sopenharmony_ci	u64 attr_offset;
366562306a36Sopenharmony_ci	int err;
366662306a36Sopenharmony_ci
366762306a36Sopenharmony_ci	ff = (struct feat_fd){ .fd = fd};
366862306a36Sopenharmony_ci	lseek(fd, sizeof(f_header), SEEK_SET);
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
367162306a36Sopenharmony_ci		evsel->id_offset = lseek(fd, 0, SEEK_CUR);
367262306a36Sopenharmony_ci		err = do_write(&ff, evsel->core.id, evsel->core.ids * sizeof(u64));
367362306a36Sopenharmony_ci		if (err < 0) {
367462306a36Sopenharmony_ci			pr_debug("failed to write perf header\n");
367562306a36Sopenharmony_ci			return err;
367662306a36Sopenharmony_ci		}
367762306a36Sopenharmony_ci	}
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ci	attr_offset = lseek(ff.fd, 0, SEEK_CUR);
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
368262306a36Sopenharmony_ci		if (evsel->core.attr.size < sizeof(evsel->core.attr)) {
368362306a36Sopenharmony_ci			/*
368462306a36Sopenharmony_ci			 * We are likely in "perf inject" and have read
368562306a36Sopenharmony_ci			 * from an older file. Update attr size so that
368662306a36Sopenharmony_ci			 * reader gets the right offset to the ids.
368762306a36Sopenharmony_ci			 */
368862306a36Sopenharmony_ci			evsel->core.attr.size = sizeof(evsel->core.attr);
368962306a36Sopenharmony_ci		}
369062306a36Sopenharmony_ci		f_attr = (struct perf_file_attr){
369162306a36Sopenharmony_ci			.attr = evsel->core.attr,
369262306a36Sopenharmony_ci			.ids  = {
369362306a36Sopenharmony_ci				.offset = evsel->id_offset,
369462306a36Sopenharmony_ci				.size   = evsel->core.ids * sizeof(u64),
369562306a36Sopenharmony_ci			}
369662306a36Sopenharmony_ci		};
369762306a36Sopenharmony_ci		err = do_write(&ff, &f_attr, sizeof(f_attr));
369862306a36Sopenharmony_ci		if (err < 0) {
369962306a36Sopenharmony_ci			pr_debug("failed to write perf header attribute\n");
370062306a36Sopenharmony_ci			return err;
370162306a36Sopenharmony_ci		}
370262306a36Sopenharmony_ci	}
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	if (!header->data_offset)
370562306a36Sopenharmony_ci		header->data_offset = lseek(fd, 0, SEEK_CUR);
370662306a36Sopenharmony_ci	header->feat_offset = header->data_offset + header->data_size;
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	if (at_exit) {
370962306a36Sopenharmony_ci		err = perf_header__adds_write(header, evlist, fd, fc);
371062306a36Sopenharmony_ci		if (err < 0)
371162306a36Sopenharmony_ci			return err;
371262306a36Sopenharmony_ci	}
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci	f_header = (struct perf_file_header){
371562306a36Sopenharmony_ci		.magic	   = PERF_MAGIC,
371662306a36Sopenharmony_ci		.size	   = sizeof(f_header),
371762306a36Sopenharmony_ci		.attr_size = sizeof(f_attr),
371862306a36Sopenharmony_ci		.attrs = {
371962306a36Sopenharmony_ci			.offset = attr_offset,
372062306a36Sopenharmony_ci			.size   = evlist->core.nr_entries * sizeof(f_attr),
372162306a36Sopenharmony_ci		},
372262306a36Sopenharmony_ci		.data = {
372362306a36Sopenharmony_ci			.offset = header->data_offset,
372462306a36Sopenharmony_ci			.size	= header->data_size,
372562306a36Sopenharmony_ci		},
372662306a36Sopenharmony_ci		/* event_types is ignored, store zeros */
372762306a36Sopenharmony_ci	};
372862306a36Sopenharmony_ci
372962306a36Sopenharmony_ci	memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features));
373062306a36Sopenharmony_ci
373162306a36Sopenharmony_ci	lseek(fd, 0, SEEK_SET);
373262306a36Sopenharmony_ci	err = do_write(&ff, &f_header, sizeof(f_header));
373362306a36Sopenharmony_ci	if (err < 0) {
373462306a36Sopenharmony_ci		pr_debug("failed to write perf header\n");
373562306a36Sopenharmony_ci		return err;
373662306a36Sopenharmony_ci	}
373762306a36Sopenharmony_ci	lseek(fd, header->data_offset + header->data_size, SEEK_SET);
373862306a36Sopenharmony_ci
373962306a36Sopenharmony_ci	return 0;
374062306a36Sopenharmony_ci}
374162306a36Sopenharmony_ci
374262306a36Sopenharmony_ciint perf_session__write_header(struct perf_session *session,
374362306a36Sopenharmony_ci			       struct evlist *evlist,
374462306a36Sopenharmony_ci			       int fd, bool at_exit)
374562306a36Sopenharmony_ci{
374662306a36Sopenharmony_ci	return perf_session__do_write_header(session, evlist, fd, at_exit, NULL);
374762306a36Sopenharmony_ci}
374862306a36Sopenharmony_ci
374962306a36Sopenharmony_cisize_t perf_session__data_offset(const struct evlist *evlist)
375062306a36Sopenharmony_ci{
375162306a36Sopenharmony_ci	struct evsel *evsel;
375262306a36Sopenharmony_ci	size_t data_offset;
375362306a36Sopenharmony_ci
375462306a36Sopenharmony_ci	data_offset = sizeof(struct perf_file_header);
375562306a36Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
375662306a36Sopenharmony_ci		data_offset += evsel->core.ids * sizeof(u64);
375762306a36Sopenharmony_ci	}
375862306a36Sopenharmony_ci	data_offset += evlist->core.nr_entries * sizeof(struct perf_file_attr);
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci	return data_offset;
376162306a36Sopenharmony_ci}
376262306a36Sopenharmony_ci
376362306a36Sopenharmony_ciint perf_session__inject_header(struct perf_session *session,
376462306a36Sopenharmony_ci				struct evlist *evlist,
376562306a36Sopenharmony_ci				int fd,
376662306a36Sopenharmony_ci				struct feat_copier *fc)
376762306a36Sopenharmony_ci{
376862306a36Sopenharmony_ci	return perf_session__do_write_header(session, evlist, fd, true, fc);
376962306a36Sopenharmony_ci}
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_cistatic int perf_header__getbuffer64(struct perf_header *header,
377262306a36Sopenharmony_ci				    int fd, void *buf, size_t size)
377362306a36Sopenharmony_ci{
377462306a36Sopenharmony_ci	if (readn(fd, buf, size) <= 0)
377562306a36Sopenharmony_ci		return -1;
377662306a36Sopenharmony_ci
377762306a36Sopenharmony_ci	if (header->needs_swap)
377862306a36Sopenharmony_ci		mem_bswap_64(buf, size);
377962306a36Sopenharmony_ci
378062306a36Sopenharmony_ci	return 0;
378162306a36Sopenharmony_ci}
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ciint perf_header__process_sections(struct perf_header *header, int fd,
378462306a36Sopenharmony_ci				  void *data,
378562306a36Sopenharmony_ci				  int (*process)(struct perf_file_section *section,
378662306a36Sopenharmony_ci						 struct perf_header *ph,
378762306a36Sopenharmony_ci						 int feat, int fd, void *data))
378862306a36Sopenharmony_ci{
378962306a36Sopenharmony_ci	struct perf_file_section *feat_sec, *sec;
379062306a36Sopenharmony_ci	int nr_sections;
379162306a36Sopenharmony_ci	int sec_size;
379262306a36Sopenharmony_ci	int feat;
379362306a36Sopenharmony_ci	int err;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS);
379662306a36Sopenharmony_ci	if (!nr_sections)
379762306a36Sopenharmony_ci		return 0;
379862306a36Sopenharmony_ci
379962306a36Sopenharmony_ci	feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec));
380062306a36Sopenharmony_ci	if (!feat_sec)
380162306a36Sopenharmony_ci		return -1;
380262306a36Sopenharmony_ci
380362306a36Sopenharmony_ci	sec_size = sizeof(*feat_sec) * nr_sections;
380462306a36Sopenharmony_ci
380562306a36Sopenharmony_ci	lseek(fd, header->feat_offset, SEEK_SET);
380662306a36Sopenharmony_ci
380762306a36Sopenharmony_ci	err = perf_header__getbuffer64(header, fd, feat_sec, sec_size);
380862306a36Sopenharmony_ci	if (err < 0)
380962306a36Sopenharmony_ci		goto out_free;
381062306a36Sopenharmony_ci
381162306a36Sopenharmony_ci	for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) {
381262306a36Sopenharmony_ci		err = process(sec++, header, feat, fd, data);
381362306a36Sopenharmony_ci		if (err < 0)
381462306a36Sopenharmony_ci			goto out_free;
381562306a36Sopenharmony_ci	}
381662306a36Sopenharmony_ci	err = 0;
381762306a36Sopenharmony_ciout_free:
381862306a36Sopenharmony_ci	free(feat_sec);
381962306a36Sopenharmony_ci	return err;
382062306a36Sopenharmony_ci}
382162306a36Sopenharmony_ci
382262306a36Sopenharmony_cistatic const int attr_file_abi_sizes[] = {
382362306a36Sopenharmony_ci	[0] = PERF_ATTR_SIZE_VER0,
382462306a36Sopenharmony_ci	[1] = PERF_ATTR_SIZE_VER1,
382562306a36Sopenharmony_ci	[2] = PERF_ATTR_SIZE_VER2,
382662306a36Sopenharmony_ci	[3] = PERF_ATTR_SIZE_VER3,
382762306a36Sopenharmony_ci	[4] = PERF_ATTR_SIZE_VER4,
382862306a36Sopenharmony_ci	0,
382962306a36Sopenharmony_ci};
383062306a36Sopenharmony_ci
383162306a36Sopenharmony_ci/*
383262306a36Sopenharmony_ci * In the legacy file format, the magic number is not used to encode endianness.
383362306a36Sopenharmony_ci * hdr_sz was used to encode endianness. But given that hdr_sz can vary based
383462306a36Sopenharmony_ci * on ABI revisions, we need to try all combinations for all endianness to
383562306a36Sopenharmony_ci * detect the endianness.
383662306a36Sopenharmony_ci */
383762306a36Sopenharmony_cistatic int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph)
383862306a36Sopenharmony_ci{
383962306a36Sopenharmony_ci	uint64_t ref_size, attr_size;
384062306a36Sopenharmony_ci	int i;
384162306a36Sopenharmony_ci
384262306a36Sopenharmony_ci	for (i = 0 ; attr_file_abi_sizes[i]; i++) {
384362306a36Sopenharmony_ci		ref_size = attr_file_abi_sizes[i]
384462306a36Sopenharmony_ci			 + sizeof(struct perf_file_section);
384562306a36Sopenharmony_ci		if (hdr_sz != ref_size) {
384662306a36Sopenharmony_ci			attr_size = bswap_64(hdr_sz);
384762306a36Sopenharmony_ci			if (attr_size != ref_size)
384862306a36Sopenharmony_ci				continue;
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci			ph->needs_swap = true;
385162306a36Sopenharmony_ci		}
385262306a36Sopenharmony_ci		pr_debug("ABI%d perf.data file detected, need_swap=%d\n",
385362306a36Sopenharmony_ci			 i,
385462306a36Sopenharmony_ci			 ph->needs_swap);
385562306a36Sopenharmony_ci		return 0;
385662306a36Sopenharmony_ci	}
385762306a36Sopenharmony_ci	/* could not determine endianness */
385862306a36Sopenharmony_ci	return -1;
385962306a36Sopenharmony_ci}
386062306a36Sopenharmony_ci
386162306a36Sopenharmony_ci#define PERF_PIPE_HDR_VER0	16
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_cistatic const size_t attr_pipe_abi_sizes[] = {
386462306a36Sopenharmony_ci	[0] = PERF_PIPE_HDR_VER0,
386562306a36Sopenharmony_ci	0,
386662306a36Sopenharmony_ci};
386762306a36Sopenharmony_ci
386862306a36Sopenharmony_ci/*
386962306a36Sopenharmony_ci * In the legacy pipe format, there is an implicit assumption that endianness
387062306a36Sopenharmony_ci * between host recording the samples, and host parsing the samples is the
387162306a36Sopenharmony_ci * same. This is not always the case given that the pipe output may always be
387262306a36Sopenharmony_ci * redirected into a file and analyzed on a different machine with possibly a
387362306a36Sopenharmony_ci * different endianness and perf_event ABI revisions in the perf tool itself.
387462306a36Sopenharmony_ci */
387562306a36Sopenharmony_cistatic int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph)
387662306a36Sopenharmony_ci{
387762306a36Sopenharmony_ci	u64 attr_size;
387862306a36Sopenharmony_ci	int i;
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci	for (i = 0 ; attr_pipe_abi_sizes[i]; i++) {
388162306a36Sopenharmony_ci		if (hdr_sz != attr_pipe_abi_sizes[i]) {
388262306a36Sopenharmony_ci			attr_size = bswap_64(hdr_sz);
388362306a36Sopenharmony_ci			if (attr_size != hdr_sz)
388462306a36Sopenharmony_ci				continue;
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci			ph->needs_swap = true;
388762306a36Sopenharmony_ci		}
388862306a36Sopenharmony_ci		pr_debug("Pipe ABI%d perf.data file detected\n", i);
388962306a36Sopenharmony_ci		return 0;
389062306a36Sopenharmony_ci	}
389162306a36Sopenharmony_ci	return -1;
389262306a36Sopenharmony_ci}
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_cibool is_perf_magic(u64 magic)
389562306a36Sopenharmony_ci{
389662306a36Sopenharmony_ci	if (!memcmp(&magic, __perf_magic1, sizeof(magic))
389762306a36Sopenharmony_ci		|| magic == __perf_magic2
389862306a36Sopenharmony_ci		|| magic == __perf_magic2_sw)
389962306a36Sopenharmony_ci		return true;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	return false;
390262306a36Sopenharmony_ci}
390362306a36Sopenharmony_ci
390462306a36Sopenharmony_cistatic int check_magic_endian(u64 magic, uint64_t hdr_sz,
390562306a36Sopenharmony_ci			      bool is_pipe, struct perf_header *ph)
390662306a36Sopenharmony_ci{
390762306a36Sopenharmony_ci	int ret;
390862306a36Sopenharmony_ci
390962306a36Sopenharmony_ci	/* check for legacy format */
391062306a36Sopenharmony_ci	ret = memcmp(&magic, __perf_magic1, sizeof(magic));
391162306a36Sopenharmony_ci	if (ret == 0) {
391262306a36Sopenharmony_ci		ph->version = PERF_HEADER_VERSION_1;
391362306a36Sopenharmony_ci		pr_debug("legacy perf.data format\n");
391462306a36Sopenharmony_ci		if (is_pipe)
391562306a36Sopenharmony_ci			return try_all_pipe_abis(hdr_sz, ph);
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci		return try_all_file_abis(hdr_sz, ph);
391862306a36Sopenharmony_ci	}
391962306a36Sopenharmony_ci	/*
392062306a36Sopenharmony_ci	 * the new magic number serves two purposes:
392162306a36Sopenharmony_ci	 * - unique number to identify actual perf.data files
392262306a36Sopenharmony_ci	 * - encode endianness of file
392362306a36Sopenharmony_ci	 */
392462306a36Sopenharmony_ci	ph->version = PERF_HEADER_VERSION_2;
392562306a36Sopenharmony_ci
392662306a36Sopenharmony_ci	/* check magic number with one endianness */
392762306a36Sopenharmony_ci	if (magic == __perf_magic2)
392862306a36Sopenharmony_ci		return 0;
392962306a36Sopenharmony_ci
393062306a36Sopenharmony_ci	/* check magic number with opposite endianness */
393162306a36Sopenharmony_ci	if (magic != __perf_magic2_sw)
393262306a36Sopenharmony_ci		return -1;
393362306a36Sopenharmony_ci
393462306a36Sopenharmony_ci	ph->needs_swap = true;
393562306a36Sopenharmony_ci
393662306a36Sopenharmony_ci	return 0;
393762306a36Sopenharmony_ci}
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ciint perf_file_header__read(struct perf_file_header *header,
394062306a36Sopenharmony_ci			   struct perf_header *ph, int fd)
394162306a36Sopenharmony_ci{
394262306a36Sopenharmony_ci	ssize_t ret;
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	lseek(fd, 0, SEEK_SET);
394562306a36Sopenharmony_ci
394662306a36Sopenharmony_ci	ret = readn(fd, header, sizeof(*header));
394762306a36Sopenharmony_ci	if (ret <= 0)
394862306a36Sopenharmony_ci		return -1;
394962306a36Sopenharmony_ci
395062306a36Sopenharmony_ci	if (check_magic_endian(header->magic,
395162306a36Sopenharmony_ci			       header->attr_size, false, ph) < 0) {
395262306a36Sopenharmony_ci		pr_debug("magic/endian check failed\n");
395362306a36Sopenharmony_ci		return -1;
395462306a36Sopenharmony_ci	}
395562306a36Sopenharmony_ci
395662306a36Sopenharmony_ci	if (ph->needs_swap) {
395762306a36Sopenharmony_ci		mem_bswap_64(header, offsetof(struct perf_file_header,
395862306a36Sopenharmony_ci			     adds_features));
395962306a36Sopenharmony_ci	}
396062306a36Sopenharmony_ci
396162306a36Sopenharmony_ci	if (header->size != sizeof(*header)) {
396262306a36Sopenharmony_ci		/* Support the previous format */
396362306a36Sopenharmony_ci		if (header->size == offsetof(typeof(*header), adds_features))
396462306a36Sopenharmony_ci			bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
396562306a36Sopenharmony_ci		else
396662306a36Sopenharmony_ci			return -1;
396762306a36Sopenharmony_ci	} else if (ph->needs_swap) {
396862306a36Sopenharmony_ci		/*
396962306a36Sopenharmony_ci		 * feature bitmap is declared as an array of unsigned longs --
397062306a36Sopenharmony_ci		 * not good since its size can differ between the host that
397162306a36Sopenharmony_ci		 * generated the data file and the host analyzing the file.
397262306a36Sopenharmony_ci		 *
397362306a36Sopenharmony_ci		 * We need to handle endianness, but we don't know the size of
397462306a36Sopenharmony_ci		 * the unsigned long where the file was generated. Take a best
397562306a36Sopenharmony_ci		 * guess at determining it: try 64-bit swap first (ie., file
397662306a36Sopenharmony_ci		 * created on a 64-bit host), and check if the hostname feature
397762306a36Sopenharmony_ci		 * bit is set (this feature bit is forced on as of fbe96f2).
397862306a36Sopenharmony_ci		 * If the bit is not, undo the 64-bit swap and try a 32-bit
397962306a36Sopenharmony_ci		 * swap. If the hostname bit is still not set (e.g., older data
398062306a36Sopenharmony_ci		 * file), punt and fallback to the original behavior --
398162306a36Sopenharmony_ci		 * clearing all feature bits and setting buildid.
398262306a36Sopenharmony_ci		 */
398362306a36Sopenharmony_ci		mem_bswap_64(&header->adds_features,
398462306a36Sopenharmony_ci			    BITS_TO_U64(HEADER_FEAT_BITS));
398562306a36Sopenharmony_ci
398662306a36Sopenharmony_ci		if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
398762306a36Sopenharmony_ci			/* unswap as u64 */
398862306a36Sopenharmony_ci			mem_bswap_64(&header->adds_features,
398962306a36Sopenharmony_ci				    BITS_TO_U64(HEADER_FEAT_BITS));
399062306a36Sopenharmony_ci
399162306a36Sopenharmony_ci			/* unswap as u32 */
399262306a36Sopenharmony_ci			mem_bswap_32(&header->adds_features,
399362306a36Sopenharmony_ci				    BITS_TO_U32(HEADER_FEAT_BITS));
399462306a36Sopenharmony_ci		}
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci		if (!test_bit(HEADER_HOSTNAME, header->adds_features)) {
399762306a36Sopenharmony_ci			bitmap_zero(header->adds_features, HEADER_FEAT_BITS);
399862306a36Sopenharmony_ci			__set_bit(HEADER_BUILD_ID, header->adds_features);
399962306a36Sopenharmony_ci		}
400062306a36Sopenharmony_ci	}
400162306a36Sopenharmony_ci
400262306a36Sopenharmony_ci	memcpy(&ph->adds_features, &header->adds_features,
400362306a36Sopenharmony_ci	       sizeof(ph->adds_features));
400462306a36Sopenharmony_ci
400562306a36Sopenharmony_ci	ph->data_offset  = header->data.offset;
400662306a36Sopenharmony_ci	ph->data_size	 = header->data.size;
400762306a36Sopenharmony_ci	ph->feat_offset  = header->data.offset + header->data.size;
400862306a36Sopenharmony_ci	return 0;
400962306a36Sopenharmony_ci}
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_cistatic int perf_file_section__process(struct perf_file_section *section,
401262306a36Sopenharmony_ci				      struct perf_header *ph,
401362306a36Sopenharmony_ci				      int feat, int fd, void *data)
401462306a36Sopenharmony_ci{
401562306a36Sopenharmony_ci	struct feat_fd fdd = {
401662306a36Sopenharmony_ci		.fd	= fd,
401762306a36Sopenharmony_ci		.ph	= ph,
401862306a36Sopenharmony_ci		.size	= section->size,
401962306a36Sopenharmony_ci		.offset	= section->offset,
402062306a36Sopenharmony_ci	};
402162306a36Sopenharmony_ci
402262306a36Sopenharmony_ci	if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) {
402362306a36Sopenharmony_ci		pr_debug("Failed to lseek to %" PRIu64 " offset for feature "
402462306a36Sopenharmony_ci			  "%d, continuing...\n", section->offset, feat);
402562306a36Sopenharmony_ci		return 0;
402662306a36Sopenharmony_ci	}
402762306a36Sopenharmony_ci
402862306a36Sopenharmony_ci	if (feat >= HEADER_LAST_FEATURE) {
402962306a36Sopenharmony_ci		pr_debug("unknown feature %d, continuing...\n", feat);
403062306a36Sopenharmony_ci		return 0;
403162306a36Sopenharmony_ci	}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci	if (!feat_ops[feat].process)
403462306a36Sopenharmony_ci		return 0;
403562306a36Sopenharmony_ci
403662306a36Sopenharmony_ci	return feat_ops[feat].process(&fdd, data);
403762306a36Sopenharmony_ci}
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_cistatic int perf_file_header__read_pipe(struct perf_pipe_file_header *header,
404062306a36Sopenharmony_ci				       struct perf_header *ph,
404162306a36Sopenharmony_ci				       struct perf_data* data,
404262306a36Sopenharmony_ci				       bool repipe, int repipe_fd)
404362306a36Sopenharmony_ci{
404462306a36Sopenharmony_ci	struct feat_fd ff = {
404562306a36Sopenharmony_ci		.fd = repipe_fd,
404662306a36Sopenharmony_ci		.ph = ph,
404762306a36Sopenharmony_ci	};
404862306a36Sopenharmony_ci	ssize_t ret;
404962306a36Sopenharmony_ci
405062306a36Sopenharmony_ci	ret = perf_data__read(data, header, sizeof(*header));
405162306a36Sopenharmony_ci	if (ret <= 0)
405262306a36Sopenharmony_ci		return -1;
405362306a36Sopenharmony_ci
405462306a36Sopenharmony_ci	if (check_magic_endian(header->magic, header->size, true, ph) < 0) {
405562306a36Sopenharmony_ci		pr_debug("endian/magic failed\n");
405662306a36Sopenharmony_ci		return -1;
405762306a36Sopenharmony_ci	}
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci	if (ph->needs_swap)
406062306a36Sopenharmony_ci		header->size = bswap_64(header->size);
406162306a36Sopenharmony_ci
406262306a36Sopenharmony_ci	if (repipe && do_write(&ff, header, sizeof(*header)) < 0)
406362306a36Sopenharmony_ci		return -1;
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci	return 0;
406662306a36Sopenharmony_ci}
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_cistatic int perf_header__read_pipe(struct perf_session *session, int repipe_fd)
406962306a36Sopenharmony_ci{
407062306a36Sopenharmony_ci	struct perf_header *header = &session->header;
407162306a36Sopenharmony_ci	struct perf_pipe_file_header f_header;
407262306a36Sopenharmony_ci
407362306a36Sopenharmony_ci	if (perf_file_header__read_pipe(&f_header, header, session->data,
407462306a36Sopenharmony_ci					session->repipe, repipe_fd) < 0) {
407562306a36Sopenharmony_ci		pr_debug("incompatible file format\n");
407662306a36Sopenharmony_ci		return -EINVAL;
407762306a36Sopenharmony_ci	}
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	return f_header.size == sizeof(f_header) ? 0 : -1;
408062306a36Sopenharmony_ci}
408162306a36Sopenharmony_ci
408262306a36Sopenharmony_cistatic int read_attr(int fd, struct perf_header *ph,
408362306a36Sopenharmony_ci		     struct perf_file_attr *f_attr)
408462306a36Sopenharmony_ci{
408562306a36Sopenharmony_ci	struct perf_event_attr *attr = &f_attr->attr;
408662306a36Sopenharmony_ci	size_t sz, left;
408762306a36Sopenharmony_ci	size_t our_sz = sizeof(f_attr->attr);
408862306a36Sopenharmony_ci	ssize_t ret;
408962306a36Sopenharmony_ci
409062306a36Sopenharmony_ci	memset(f_attr, 0, sizeof(*f_attr));
409162306a36Sopenharmony_ci
409262306a36Sopenharmony_ci	/* read minimal guaranteed structure */
409362306a36Sopenharmony_ci	ret = readn(fd, attr, PERF_ATTR_SIZE_VER0);
409462306a36Sopenharmony_ci	if (ret <= 0) {
409562306a36Sopenharmony_ci		pr_debug("cannot read %d bytes of header attr\n",
409662306a36Sopenharmony_ci			 PERF_ATTR_SIZE_VER0);
409762306a36Sopenharmony_ci		return -1;
409862306a36Sopenharmony_ci	}
409962306a36Sopenharmony_ci
410062306a36Sopenharmony_ci	/* on file perf_event_attr size */
410162306a36Sopenharmony_ci	sz = attr->size;
410262306a36Sopenharmony_ci
410362306a36Sopenharmony_ci	if (ph->needs_swap)
410462306a36Sopenharmony_ci		sz = bswap_32(sz);
410562306a36Sopenharmony_ci
410662306a36Sopenharmony_ci	if (sz == 0) {
410762306a36Sopenharmony_ci		/* assume ABI0 */
410862306a36Sopenharmony_ci		sz =  PERF_ATTR_SIZE_VER0;
410962306a36Sopenharmony_ci	} else if (sz > our_sz) {
411062306a36Sopenharmony_ci		pr_debug("file uses a more recent and unsupported ABI"
411162306a36Sopenharmony_ci			 " (%zu bytes extra)\n", sz - our_sz);
411262306a36Sopenharmony_ci		return -1;
411362306a36Sopenharmony_ci	}
411462306a36Sopenharmony_ci	/* what we have not yet read and that we know about */
411562306a36Sopenharmony_ci	left = sz - PERF_ATTR_SIZE_VER0;
411662306a36Sopenharmony_ci	if (left) {
411762306a36Sopenharmony_ci		void *ptr = attr;
411862306a36Sopenharmony_ci		ptr += PERF_ATTR_SIZE_VER0;
411962306a36Sopenharmony_ci
412062306a36Sopenharmony_ci		ret = readn(fd, ptr, left);
412162306a36Sopenharmony_ci	}
412262306a36Sopenharmony_ci	/* read perf_file_section, ids are read in caller */
412362306a36Sopenharmony_ci	ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids));
412462306a36Sopenharmony_ci
412562306a36Sopenharmony_ci	return ret <= 0 ? -1 : 0;
412662306a36Sopenharmony_ci}
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
412962306a36Sopenharmony_cistatic int evsel__prepare_tracepoint_event(struct evsel *evsel, struct tep_handle *pevent)
413062306a36Sopenharmony_ci{
413162306a36Sopenharmony_ci	struct tep_event *event;
413262306a36Sopenharmony_ci	char bf[128];
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	/* already prepared */
413562306a36Sopenharmony_ci	if (evsel->tp_format)
413662306a36Sopenharmony_ci		return 0;
413762306a36Sopenharmony_ci
413862306a36Sopenharmony_ci	if (pevent == NULL) {
413962306a36Sopenharmony_ci		pr_debug("broken or missing trace data\n");
414062306a36Sopenharmony_ci		return -1;
414162306a36Sopenharmony_ci	}
414262306a36Sopenharmony_ci
414362306a36Sopenharmony_ci	event = tep_find_event(pevent, evsel->core.attr.config);
414462306a36Sopenharmony_ci	if (event == NULL) {
414562306a36Sopenharmony_ci		pr_debug("cannot find event format for %d\n", (int)evsel->core.attr.config);
414662306a36Sopenharmony_ci		return -1;
414762306a36Sopenharmony_ci	}
414862306a36Sopenharmony_ci
414962306a36Sopenharmony_ci	if (!evsel->name) {
415062306a36Sopenharmony_ci		snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name);
415162306a36Sopenharmony_ci		evsel->name = strdup(bf);
415262306a36Sopenharmony_ci		if (evsel->name == NULL)
415362306a36Sopenharmony_ci			return -1;
415462306a36Sopenharmony_ci	}
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ci	evsel->tp_format = event;
415762306a36Sopenharmony_ci	return 0;
415862306a36Sopenharmony_ci}
415962306a36Sopenharmony_ci
416062306a36Sopenharmony_cistatic int evlist__prepare_tracepoint_events(struct evlist *evlist, struct tep_handle *pevent)
416162306a36Sopenharmony_ci{
416262306a36Sopenharmony_ci	struct evsel *pos;
416362306a36Sopenharmony_ci
416462306a36Sopenharmony_ci	evlist__for_each_entry(evlist, pos) {
416562306a36Sopenharmony_ci		if (pos->core.attr.type == PERF_TYPE_TRACEPOINT &&
416662306a36Sopenharmony_ci		    evsel__prepare_tracepoint_event(pos, pevent))
416762306a36Sopenharmony_ci			return -1;
416862306a36Sopenharmony_ci	}
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	return 0;
417162306a36Sopenharmony_ci}
417262306a36Sopenharmony_ci#endif
417362306a36Sopenharmony_ci
417462306a36Sopenharmony_ciint perf_session__read_header(struct perf_session *session, int repipe_fd)
417562306a36Sopenharmony_ci{
417662306a36Sopenharmony_ci	struct perf_data *data = session->data;
417762306a36Sopenharmony_ci	struct perf_header *header = &session->header;
417862306a36Sopenharmony_ci	struct perf_file_header	f_header;
417962306a36Sopenharmony_ci	struct perf_file_attr	f_attr;
418062306a36Sopenharmony_ci	u64			f_id;
418162306a36Sopenharmony_ci	int nr_attrs, nr_ids, i, j, err;
418262306a36Sopenharmony_ci	int fd = perf_data__fd(data);
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_ci	session->evlist = evlist__new();
418562306a36Sopenharmony_ci	if (session->evlist == NULL)
418662306a36Sopenharmony_ci		return -ENOMEM;
418762306a36Sopenharmony_ci
418862306a36Sopenharmony_ci	session->evlist->env = &header->env;
418962306a36Sopenharmony_ci	session->machines.host.env = &header->env;
419062306a36Sopenharmony_ci
419162306a36Sopenharmony_ci	/*
419262306a36Sopenharmony_ci	 * We can read 'pipe' data event from regular file,
419362306a36Sopenharmony_ci	 * check for the pipe header regardless of source.
419462306a36Sopenharmony_ci	 */
419562306a36Sopenharmony_ci	err = perf_header__read_pipe(session, repipe_fd);
419662306a36Sopenharmony_ci	if (!err || perf_data__is_pipe(data)) {
419762306a36Sopenharmony_ci		data->is_pipe = true;
419862306a36Sopenharmony_ci		return err;
419962306a36Sopenharmony_ci	}
420062306a36Sopenharmony_ci
420162306a36Sopenharmony_ci	if (perf_file_header__read(&f_header, header, fd) < 0)
420262306a36Sopenharmony_ci		return -EINVAL;
420362306a36Sopenharmony_ci
420462306a36Sopenharmony_ci	if (header->needs_swap && data->in_place_update) {
420562306a36Sopenharmony_ci		pr_err("In-place update not supported when byte-swapping is required\n");
420662306a36Sopenharmony_ci		return -EINVAL;
420762306a36Sopenharmony_ci	}
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci	/*
421062306a36Sopenharmony_ci	 * Sanity check that perf.data was written cleanly; data size is
421162306a36Sopenharmony_ci	 * initialized to 0 and updated only if the on_exit function is run.
421262306a36Sopenharmony_ci	 * If data size is still 0 then the file contains only partial
421362306a36Sopenharmony_ci	 * information.  Just warn user and process it as much as it can.
421462306a36Sopenharmony_ci	 */
421562306a36Sopenharmony_ci	if (f_header.data.size == 0) {
421662306a36Sopenharmony_ci		pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n"
421762306a36Sopenharmony_ci			   "Was the 'perf record' command properly terminated?\n",
421862306a36Sopenharmony_ci			   data->file.path);
421962306a36Sopenharmony_ci	}
422062306a36Sopenharmony_ci
422162306a36Sopenharmony_ci	if (f_header.attr_size == 0) {
422262306a36Sopenharmony_ci		pr_err("ERROR: The %s file's attr size field is 0 which is unexpected.\n"
422362306a36Sopenharmony_ci		       "Was the 'perf record' command properly terminated?\n",
422462306a36Sopenharmony_ci		       data->file.path);
422562306a36Sopenharmony_ci		return -EINVAL;
422662306a36Sopenharmony_ci	}
422762306a36Sopenharmony_ci
422862306a36Sopenharmony_ci	nr_attrs = f_header.attrs.size / f_header.attr_size;
422962306a36Sopenharmony_ci	lseek(fd, f_header.attrs.offset, SEEK_SET);
423062306a36Sopenharmony_ci
423162306a36Sopenharmony_ci	for (i = 0; i < nr_attrs; i++) {
423262306a36Sopenharmony_ci		struct evsel *evsel;
423362306a36Sopenharmony_ci		off_t tmp;
423462306a36Sopenharmony_ci
423562306a36Sopenharmony_ci		if (read_attr(fd, header, &f_attr) < 0)
423662306a36Sopenharmony_ci			goto out_errno;
423762306a36Sopenharmony_ci
423862306a36Sopenharmony_ci		if (header->needs_swap) {
423962306a36Sopenharmony_ci			f_attr.ids.size   = bswap_64(f_attr.ids.size);
424062306a36Sopenharmony_ci			f_attr.ids.offset = bswap_64(f_attr.ids.offset);
424162306a36Sopenharmony_ci			perf_event__attr_swap(&f_attr.attr);
424262306a36Sopenharmony_ci		}
424362306a36Sopenharmony_ci
424462306a36Sopenharmony_ci		tmp = lseek(fd, 0, SEEK_CUR);
424562306a36Sopenharmony_ci		evsel = evsel__new(&f_attr.attr);
424662306a36Sopenharmony_ci
424762306a36Sopenharmony_ci		if (evsel == NULL)
424862306a36Sopenharmony_ci			goto out_delete_evlist;
424962306a36Sopenharmony_ci
425062306a36Sopenharmony_ci		evsel->needs_swap = header->needs_swap;
425162306a36Sopenharmony_ci		/*
425262306a36Sopenharmony_ci		 * Do it before so that if perf_evsel__alloc_id fails, this
425362306a36Sopenharmony_ci		 * entry gets purged too at evlist__delete().
425462306a36Sopenharmony_ci		 */
425562306a36Sopenharmony_ci		evlist__add(session->evlist, evsel);
425662306a36Sopenharmony_ci
425762306a36Sopenharmony_ci		nr_ids = f_attr.ids.size / sizeof(u64);
425862306a36Sopenharmony_ci		/*
425962306a36Sopenharmony_ci		 * We don't have the cpu and thread maps on the header, so
426062306a36Sopenharmony_ci		 * for allocating the perf_sample_id table we fake 1 cpu and
426162306a36Sopenharmony_ci		 * hattr->ids threads.
426262306a36Sopenharmony_ci		 */
426362306a36Sopenharmony_ci		if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids))
426462306a36Sopenharmony_ci			goto out_delete_evlist;
426562306a36Sopenharmony_ci
426662306a36Sopenharmony_ci		lseek(fd, f_attr.ids.offset, SEEK_SET);
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci		for (j = 0; j < nr_ids; j++) {
426962306a36Sopenharmony_ci			if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id)))
427062306a36Sopenharmony_ci				goto out_errno;
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci			perf_evlist__id_add(&session->evlist->core, &evsel->core, 0, j, f_id);
427362306a36Sopenharmony_ci		}
427462306a36Sopenharmony_ci
427562306a36Sopenharmony_ci		lseek(fd, tmp, SEEK_SET);
427662306a36Sopenharmony_ci	}
427762306a36Sopenharmony_ci
427862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
427962306a36Sopenharmony_ci	perf_header__process_sections(header, fd, &session->tevent,
428062306a36Sopenharmony_ci				      perf_file_section__process);
428162306a36Sopenharmony_ci
428262306a36Sopenharmony_ci	if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent))
428362306a36Sopenharmony_ci		goto out_delete_evlist;
428462306a36Sopenharmony_ci#else
428562306a36Sopenharmony_ci	perf_header__process_sections(header, fd, NULL, perf_file_section__process);
428662306a36Sopenharmony_ci#endif
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci	return 0;
428962306a36Sopenharmony_ciout_errno:
429062306a36Sopenharmony_ci	return -errno;
429162306a36Sopenharmony_ci
429262306a36Sopenharmony_ciout_delete_evlist:
429362306a36Sopenharmony_ci	evlist__delete(session->evlist);
429462306a36Sopenharmony_ci	session->evlist = NULL;
429562306a36Sopenharmony_ci	return -ENOMEM;
429662306a36Sopenharmony_ci}
429762306a36Sopenharmony_ci
429862306a36Sopenharmony_ciint perf_event__process_feature(struct perf_session *session,
429962306a36Sopenharmony_ci				union perf_event *event)
430062306a36Sopenharmony_ci{
430162306a36Sopenharmony_ci	struct perf_tool *tool = session->tool;
430262306a36Sopenharmony_ci	struct feat_fd ff = { .fd = 0 };
430362306a36Sopenharmony_ci	struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event;
430462306a36Sopenharmony_ci	int type = fe->header.type;
430562306a36Sopenharmony_ci	u64 feat = fe->feat_id;
430662306a36Sopenharmony_ci	int ret = 0;
430762306a36Sopenharmony_ci
430862306a36Sopenharmony_ci	if (type < 0 || type >= PERF_RECORD_HEADER_MAX) {
430962306a36Sopenharmony_ci		pr_warning("invalid record type %d in pipe-mode\n", type);
431062306a36Sopenharmony_ci		return 0;
431162306a36Sopenharmony_ci	}
431262306a36Sopenharmony_ci	if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) {
431362306a36Sopenharmony_ci		pr_warning("invalid record type %d in pipe-mode\n", type);
431462306a36Sopenharmony_ci		return -1;
431562306a36Sopenharmony_ci	}
431662306a36Sopenharmony_ci
431762306a36Sopenharmony_ci	if (!feat_ops[feat].process)
431862306a36Sopenharmony_ci		return 0;
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	ff.buf  = (void *)fe->data;
432162306a36Sopenharmony_ci	ff.size = event->header.size - sizeof(*fe);
432262306a36Sopenharmony_ci	ff.ph = &session->header;
432362306a36Sopenharmony_ci
432462306a36Sopenharmony_ci	if (feat_ops[feat].process(&ff, NULL)) {
432562306a36Sopenharmony_ci		ret = -1;
432662306a36Sopenharmony_ci		goto out;
432762306a36Sopenharmony_ci	}
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	if (!feat_ops[feat].print || !tool->show_feat_hdr)
433062306a36Sopenharmony_ci		goto out;
433162306a36Sopenharmony_ci
433262306a36Sopenharmony_ci	if (!feat_ops[feat].full_only ||
433362306a36Sopenharmony_ci	    tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) {
433462306a36Sopenharmony_ci		feat_ops[feat].print(&ff, stdout);
433562306a36Sopenharmony_ci	} else {
433662306a36Sopenharmony_ci		fprintf(stdout, "# %s info available, use -I to display\n",
433762306a36Sopenharmony_ci			feat_ops[feat].name);
433862306a36Sopenharmony_ci	}
433962306a36Sopenharmony_ciout:
434062306a36Sopenharmony_ci	free_event_desc(ff.events);
434162306a36Sopenharmony_ci	return ret;
434262306a36Sopenharmony_ci}
434362306a36Sopenharmony_ci
434462306a36Sopenharmony_cisize_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp)
434562306a36Sopenharmony_ci{
434662306a36Sopenharmony_ci	struct perf_record_event_update *ev = &event->event_update;
434762306a36Sopenharmony_ci	struct perf_cpu_map *map;
434862306a36Sopenharmony_ci	size_t ret;
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	ret = fprintf(fp, "\n... id:    %" PRI_lu64 "\n", ev->id);
435162306a36Sopenharmony_ci
435262306a36Sopenharmony_ci	switch (ev->type) {
435362306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__SCALE:
435462306a36Sopenharmony_ci		ret += fprintf(fp, "... scale: %f\n", ev->scale.scale);
435562306a36Sopenharmony_ci		break;
435662306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__UNIT:
435762306a36Sopenharmony_ci		ret += fprintf(fp, "... unit:  %s\n", ev->unit);
435862306a36Sopenharmony_ci		break;
435962306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__NAME:
436062306a36Sopenharmony_ci		ret += fprintf(fp, "... name:  %s\n", ev->name);
436162306a36Sopenharmony_ci		break;
436262306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__CPUS:
436362306a36Sopenharmony_ci		ret += fprintf(fp, "... ");
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci		map = cpu_map__new_data(&ev->cpus.cpus);
436662306a36Sopenharmony_ci		if (map) {
436762306a36Sopenharmony_ci			ret += cpu_map__fprintf(map, fp);
436862306a36Sopenharmony_ci			perf_cpu_map__put(map);
436962306a36Sopenharmony_ci		} else
437062306a36Sopenharmony_ci			ret += fprintf(fp, "failed to get cpus\n");
437162306a36Sopenharmony_ci		break;
437262306a36Sopenharmony_ci	default:
437362306a36Sopenharmony_ci		ret += fprintf(fp, "... unknown type\n");
437462306a36Sopenharmony_ci		break;
437562306a36Sopenharmony_ci	}
437662306a36Sopenharmony_ci
437762306a36Sopenharmony_ci	return ret;
437862306a36Sopenharmony_ci}
437962306a36Sopenharmony_ci
438062306a36Sopenharmony_ciint perf_event__process_attr(struct perf_tool *tool __maybe_unused,
438162306a36Sopenharmony_ci			     union perf_event *event,
438262306a36Sopenharmony_ci			     struct evlist **pevlist)
438362306a36Sopenharmony_ci{
438462306a36Sopenharmony_ci	u32 i, n_ids;
438562306a36Sopenharmony_ci	u64 *ids;
438662306a36Sopenharmony_ci	struct evsel *evsel;
438762306a36Sopenharmony_ci	struct evlist *evlist = *pevlist;
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci	if (evlist == NULL) {
439062306a36Sopenharmony_ci		*pevlist = evlist = evlist__new();
439162306a36Sopenharmony_ci		if (evlist == NULL)
439262306a36Sopenharmony_ci			return -ENOMEM;
439362306a36Sopenharmony_ci	}
439462306a36Sopenharmony_ci
439562306a36Sopenharmony_ci	evsel = evsel__new(&event->attr.attr);
439662306a36Sopenharmony_ci	if (evsel == NULL)
439762306a36Sopenharmony_ci		return -ENOMEM;
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_ci	evlist__add(evlist, evsel);
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci	n_ids = event->header.size - sizeof(event->header) - event->attr.attr.size;
440262306a36Sopenharmony_ci	n_ids = n_ids / sizeof(u64);
440362306a36Sopenharmony_ci	/*
440462306a36Sopenharmony_ci	 * We don't have the cpu and thread maps on the header, so
440562306a36Sopenharmony_ci	 * for allocating the perf_sample_id table we fake 1 cpu and
440662306a36Sopenharmony_ci	 * hattr->ids threads.
440762306a36Sopenharmony_ci	 */
440862306a36Sopenharmony_ci	if (perf_evsel__alloc_id(&evsel->core, 1, n_ids))
440962306a36Sopenharmony_ci		return -ENOMEM;
441062306a36Sopenharmony_ci
441162306a36Sopenharmony_ci	ids = perf_record_header_attr_id(event);
441262306a36Sopenharmony_ci	for (i = 0; i < n_ids; i++) {
441362306a36Sopenharmony_ci		perf_evlist__id_add(&evlist->core, &evsel->core, 0, i, ids[i]);
441462306a36Sopenharmony_ci	}
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci	return 0;
441762306a36Sopenharmony_ci}
441862306a36Sopenharmony_ci
441962306a36Sopenharmony_ciint perf_event__process_event_update(struct perf_tool *tool __maybe_unused,
442062306a36Sopenharmony_ci				     union perf_event *event,
442162306a36Sopenharmony_ci				     struct evlist **pevlist)
442262306a36Sopenharmony_ci{
442362306a36Sopenharmony_ci	struct perf_record_event_update *ev = &event->event_update;
442462306a36Sopenharmony_ci	struct evlist *evlist;
442562306a36Sopenharmony_ci	struct evsel *evsel;
442662306a36Sopenharmony_ci	struct perf_cpu_map *map;
442762306a36Sopenharmony_ci
442862306a36Sopenharmony_ci	if (dump_trace)
442962306a36Sopenharmony_ci		perf_event__fprintf_event_update(event, stdout);
443062306a36Sopenharmony_ci
443162306a36Sopenharmony_ci	if (!pevlist || *pevlist == NULL)
443262306a36Sopenharmony_ci		return -EINVAL;
443362306a36Sopenharmony_ci
443462306a36Sopenharmony_ci	evlist = *pevlist;
443562306a36Sopenharmony_ci
443662306a36Sopenharmony_ci	evsel = evlist__id2evsel(evlist, ev->id);
443762306a36Sopenharmony_ci	if (evsel == NULL)
443862306a36Sopenharmony_ci		return -EINVAL;
443962306a36Sopenharmony_ci
444062306a36Sopenharmony_ci	switch (ev->type) {
444162306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__UNIT:
444262306a36Sopenharmony_ci		free((char *)evsel->unit);
444362306a36Sopenharmony_ci		evsel->unit = strdup(ev->unit);
444462306a36Sopenharmony_ci		break;
444562306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__NAME:
444662306a36Sopenharmony_ci		free(evsel->name);
444762306a36Sopenharmony_ci		evsel->name = strdup(ev->name);
444862306a36Sopenharmony_ci		break;
444962306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__SCALE:
445062306a36Sopenharmony_ci		evsel->scale = ev->scale.scale;
445162306a36Sopenharmony_ci		break;
445262306a36Sopenharmony_ci	case PERF_EVENT_UPDATE__CPUS:
445362306a36Sopenharmony_ci		map = cpu_map__new_data(&ev->cpus.cpus);
445462306a36Sopenharmony_ci		if (map) {
445562306a36Sopenharmony_ci			perf_cpu_map__put(evsel->core.own_cpus);
445662306a36Sopenharmony_ci			evsel->core.own_cpus = map;
445762306a36Sopenharmony_ci		} else
445862306a36Sopenharmony_ci			pr_err("failed to get event_update cpus\n");
445962306a36Sopenharmony_ci	default:
446062306a36Sopenharmony_ci		break;
446162306a36Sopenharmony_ci	}
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	return 0;
446462306a36Sopenharmony_ci}
446562306a36Sopenharmony_ci
446662306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT
446762306a36Sopenharmony_ciint perf_event__process_tracing_data(struct perf_session *session,
446862306a36Sopenharmony_ci				     union perf_event *event)
446962306a36Sopenharmony_ci{
447062306a36Sopenharmony_ci	ssize_t size_read, padding, size = event->tracing_data.size;
447162306a36Sopenharmony_ci	int fd = perf_data__fd(session->data);
447262306a36Sopenharmony_ci	char buf[BUFSIZ];
447362306a36Sopenharmony_ci
447462306a36Sopenharmony_ci	/*
447562306a36Sopenharmony_ci	 * The pipe fd is already in proper place and in any case
447662306a36Sopenharmony_ci	 * we can't move it, and we'd screw the case where we read
447762306a36Sopenharmony_ci	 * 'pipe' data from regular file. The trace_report reads
447862306a36Sopenharmony_ci	 * data from 'fd' so we need to set it directly behind the
447962306a36Sopenharmony_ci	 * event, where the tracing data starts.
448062306a36Sopenharmony_ci	 */
448162306a36Sopenharmony_ci	if (!perf_data__is_pipe(session->data)) {
448262306a36Sopenharmony_ci		off_t offset = lseek(fd, 0, SEEK_CUR);
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci		/* setup for reading amidst mmap */
448562306a36Sopenharmony_ci		lseek(fd, offset + sizeof(struct perf_record_header_tracing_data),
448662306a36Sopenharmony_ci		      SEEK_SET);
448762306a36Sopenharmony_ci	}
448862306a36Sopenharmony_ci
448962306a36Sopenharmony_ci	size_read = trace_report(fd, &session->tevent,
449062306a36Sopenharmony_ci				 session->repipe);
449162306a36Sopenharmony_ci	padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read;
449262306a36Sopenharmony_ci
449362306a36Sopenharmony_ci	if (readn(fd, buf, padding) < 0) {
449462306a36Sopenharmony_ci		pr_err("%s: reading input file", __func__);
449562306a36Sopenharmony_ci		return -1;
449662306a36Sopenharmony_ci	}
449762306a36Sopenharmony_ci	if (session->repipe) {
449862306a36Sopenharmony_ci		int retw = write(STDOUT_FILENO, buf, padding);
449962306a36Sopenharmony_ci		if (retw <= 0 || retw != padding) {
450062306a36Sopenharmony_ci			pr_err("%s: repiping tracing data padding", __func__);
450162306a36Sopenharmony_ci			return -1;
450262306a36Sopenharmony_ci		}
450362306a36Sopenharmony_ci	}
450462306a36Sopenharmony_ci
450562306a36Sopenharmony_ci	if (size_read + padding != size) {
450662306a36Sopenharmony_ci		pr_err("%s: tracing data size mismatch", __func__);
450762306a36Sopenharmony_ci		return -1;
450862306a36Sopenharmony_ci	}
450962306a36Sopenharmony_ci
451062306a36Sopenharmony_ci	evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent);
451162306a36Sopenharmony_ci
451262306a36Sopenharmony_ci	return size_read + padding;
451362306a36Sopenharmony_ci}
451462306a36Sopenharmony_ci#endif
451562306a36Sopenharmony_ci
451662306a36Sopenharmony_ciint perf_event__process_build_id(struct perf_session *session,
451762306a36Sopenharmony_ci				 union perf_event *event)
451862306a36Sopenharmony_ci{
451962306a36Sopenharmony_ci	__event_process_build_id(&event->build_id,
452062306a36Sopenharmony_ci				 event->build_id.filename,
452162306a36Sopenharmony_ci				 session);
452262306a36Sopenharmony_ci	return 0;
452362306a36Sopenharmony_ci}
4524