18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * auxtrace.c: AUX area trace support
48c2ecf20Sopenharmony_ci * Copyright (c) 2013-2015, Intel Corporation.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <inttypes.h>
88c2ecf20Sopenharmony_ci#include <sys/types.h>
98c2ecf20Sopenharmony_ci#include <sys/mman.h>
108c2ecf20Sopenharmony_ci#include <stdbool.h>
118c2ecf20Sopenharmony_ci#include <string.h>
128c2ecf20Sopenharmony_ci#include <limits.h>
138c2ecf20Sopenharmony_ci#include <errno.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/perf_event.h>
178c2ecf20Sopenharmony_ci#include <linux/types.h>
188c2ecf20Sopenharmony_ci#include <linux/bitops.h>
198c2ecf20Sopenharmony_ci#include <linux/log2.h>
208c2ecf20Sopenharmony_ci#include <linux/string.h>
218c2ecf20Sopenharmony_ci#include <linux/time64.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include <sys/param.h>
248c2ecf20Sopenharmony_ci#include <stdlib.h>
258c2ecf20Sopenharmony_ci#include <stdio.h>
268c2ecf20Sopenharmony_ci#include <linux/list.h>
278c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci#include "evlist.h"
308c2ecf20Sopenharmony_ci#include "dso.h"
318c2ecf20Sopenharmony_ci#include "map.h"
328c2ecf20Sopenharmony_ci#include "pmu.h"
338c2ecf20Sopenharmony_ci#include "evsel.h"
348c2ecf20Sopenharmony_ci#include "evsel_config.h"
358c2ecf20Sopenharmony_ci#include "symbol.h"
368c2ecf20Sopenharmony_ci#include "util/perf_api_probe.h"
378c2ecf20Sopenharmony_ci#include "util/synthetic-events.h"
388c2ecf20Sopenharmony_ci#include "thread_map.h"
398c2ecf20Sopenharmony_ci#include "asm/bug.h"
408c2ecf20Sopenharmony_ci#include "auxtrace.h"
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#include <linux/hash.h>
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#include "event.h"
458c2ecf20Sopenharmony_ci#include "record.h"
468c2ecf20Sopenharmony_ci#include "session.h"
478c2ecf20Sopenharmony_ci#include "debug.h"
488c2ecf20Sopenharmony_ci#include <subcmd/parse-options.h>
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#include "cs-etm.h"
518c2ecf20Sopenharmony_ci#include "intel-pt.h"
528c2ecf20Sopenharmony_ci#include "intel-bts.h"
538c2ecf20Sopenharmony_ci#include "arm-spe.h"
548c2ecf20Sopenharmony_ci#include "s390-cpumsf.h"
558c2ecf20Sopenharmony_ci#include "util/mmap.h"
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#include <linux/ctype.h>
588c2ecf20Sopenharmony_ci#include "symbol/kallsyms.h"
598c2ecf20Sopenharmony_ci#include <internal/lib.h>
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci/*
628c2ecf20Sopenharmony_ci * Make a group from 'leader' to 'last', requiring that the events were not
638c2ecf20Sopenharmony_ci * already grouped to a different leader.
648c2ecf20Sopenharmony_ci */
658c2ecf20Sopenharmony_cistatic int perf_evlist__regroup(struct evlist *evlist,
668c2ecf20Sopenharmony_ci				struct evsel *leader,
678c2ecf20Sopenharmony_ci				struct evsel *last)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct evsel *evsel;
708c2ecf20Sopenharmony_ci	bool grp;
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	if (!evsel__is_group_leader(leader))
738c2ecf20Sopenharmony_ci		return -EINVAL;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	grp = false;
768c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
778c2ecf20Sopenharmony_ci		if (grp) {
788c2ecf20Sopenharmony_ci			if (!(evsel->leader == leader ||
798c2ecf20Sopenharmony_ci			     (evsel->leader == evsel &&
808c2ecf20Sopenharmony_ci			      evsel->core.nr_members <= 1)))
818c2ecf20Sopenharmony_ci				return -EINVAL;
828c2ecf20Sopenharmony_ci		} else if (evsel == leader) {
838c2ecf20Sopenharmony_ci			grp = true;
848c2ecf20Sopenharmony_ci		}
858c2ecf20Sopenharmony_ci		if (evsel == last)
868c2ecf20Sopenharmony_ci			break;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	grp = false;
908c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
918c2ecf20Sopenharmony_ci		if (grp) {
928c2ecf20Sopenharmony_ci			if (evsel->leader != leader) {
938c2ecf20Sopenharmony_ci				evsel->leader = leader;
948c2ecf20Sopenharmony_ci				if (leader->core.nr_members < 1)
958c2ecf20Sopenharmony_ci					leader->core.nr_members = 1;
968c2ecf20Sopenharmony_ci				leader->core.nr_members += 1;
978c2ecf20Sopenharmony_ci			}
988c2ecf20Sopenharmony_ci		} else if (evsel == leader) {
998c2ecf20Sopenharmony_ci			grp = true;
1008c2ecf20Sopenharmony_ci		}
1018c2ecf20Sopenharmony_ci		if (evsel == last)
1028c2ecf20Sopenharmony_ci			break;
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	return 0;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic bool auxtrace__dont_decode(struct perf_session *session)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	return !session->itrace_synth_opts ||
1118c2ecf20Sopenharmony_ci	       session->itrace_synth_opts->dont_decode;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ciint auxtrace_mmap__mmap(struct auxtrace_mmap *mm,
1158c2ecf20Sopenharmony_ci			struct auxtrace_mmap_params *mp,
1168c2ecf20Sopenharmony_ci			void *userpg, int fd)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct perf_event_mmap_page *pc = userpg;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n");
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	mm->userpg = userpg;
1238c2ecf20Sopenharmony_ci	mm->mask = mp->mask;
1248c2ecf20Sopenharmony_ci	mm->len = mp->len;
1258c2ecf20Sopenharmony_ci	mm->prev = 0;
1268c2ecf20Sopenharmony_ci	mm->idx = mp->idx;
1278c2ecf20Sopenharmony_ci	mm->tid = mp->tid;
1288c2ecf20Sopenharmony_ci	mm->cpu = mp->cpu;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!mp->len) {
1318c2ecf20Sopenharmony_ci		mm->base = NULL;
1328c2ecf20Sopenharmony_ci		return 0;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci#if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT)
1368c2ecf20Sopenharmony_ci	pr_err("Cannot use AUX area tracing mmaps\n");
1378c2ecf20Sopenharmony_ci	return -1;
1388c2ecf20Sopenharmony_ci#endif
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	pc->aux_offset = mp->offset;
1418c2ecf20Sopenharmony_ci	pc->aux_size = mp->len;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset);
1448c2ecf20Sopenharmony_ci	if (mm->base == MAP_FAILED) {
1458c2ecf20Sopenharmony_ci		pr_debug2("failed to mmap AUX area\n");
1468c2ecf20Sopenharmony_ci		mm->base = NULL;
1478c2ecf20Sopenharmony_ci		return -1;
1488c2ecf20Sopenharmony_ci	}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return 0;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_civoid auxtrace_mmap__munmap(struct auxtrace_mmap *mm)
1548c2ecf20Sopenharmony_ci{
1558c2ecf20Sopenharmony_ci	if (mm->base) {
1568c2ecf20Sopenharmony_ci		munmap(mm->base, mm->len);
1578c2ecf20Sopenharmony_ci		mm->base = NULL;
1588c2ecf20Sopenharmony_ci	}
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_civoid auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp,
1628c2ecf20Sopenharmony_ci				off_t auxtrace_offset,
1638c2ecf20Sopenharmony_ci				unsigned int auxtrace_pages,
1648c2ecf20Sopenharmony_ci				bool auxtrace_overwrite)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	if (auxtrace_pages) {
1678c2ecf20Sopenharmony_ci		mp->offset = auxtrace_offset;
1688c2ecf20Sopenharmony_ci		mp->len = auxtrace_pages * (size_t)page_size;
1698c2ecf20Sopenharmony_ci		mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0;
1708c2ecf20Sopenharmony_ci		mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE);
1718c2ecf20Sopenharmony_ci		pr_debug2("AUX area mmap length %zu\n", mp->len);
1728c2ecf20Sopenharmony_ci	} else {
1738c2ecf20Sopenharmony_ci		mp->len = 0;
1748c2ecf20Sopenharmony_ci	}
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_civoid auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp,
1788c2ecf20Sopenharmony_ci				   struct evlist *evlist, int idx,
1798c2ecf20Sopenharmony_ci				   bool per_cpu)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	mp->idx = idx;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	if (per_cpu) {
1848c2ecf20Sopenharmony_ci		mp->cpu = evlist->core.cpus->map[idx];
1858c2ecf20Sopenharmony_ci		if (evlist->core.threads)
1868c2ecf20Sopenharmony_ci			mp->tid = perf_thread_map__pid(evlist->core.threads, 0);
1878c2ecf20Sopenharmony_ci		else
1888c2ecf20Sopenharmony_ci			mp->tid = -1;
1898c2ecf20Sopenharmony_ci	} else {
1908c2ecf20Sopenharmony_ci		mp->cpu = -1;
1918c2ecf20Sopenharmony_ci		mp->tid = perf_thread_map__pid(evlist->core.threads, idx);
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci#define AUXTRACE_INIT_NR_QUEUES	32
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct auxtrace_queue *queue_array;
2008c2ecf20Sopenharmony_ci	unsigned int max_nr_queues, i;
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci	max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue);
2038c2ecf20Sopenharmony_ci	if (nr_queues > max_nr_queues)
2048c2ecf20Sopenharmony_ci		return NULL;
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue));
2078c2ecf20Sopenharmony_ci	if (!queue_array)
2088c2ecf20Sopenharmony_ci		return NULL;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	for (i = 0; i < nr_queues; i++) {
2118c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&queue_array[i].head);
2128c2ecf20Sopenharmony_ci		queue_array[i].priv = NULL;
2138c2ecf20Sopenharmony_ci	}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci	return queue_array;
2168c2ecf20Sopenharmony_ci}
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ciint auxtrace_queues__init(struct auxtrace_queues *queues)
2198c2ecf20Sopenharmony_ci{
2208c2ecf20Sopenharmony_ci	queues->nr_queues = AUXTRACE_INIT_NR_QUEUES;
2218c2ecf20Sopenharmony_ci	queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues);
2228c2ecf20Sopenharmony_ci	if (!queues->queue_array)
2238c2ecf20Sopenharmony_ci		return -ENOMEM;
2248c2ecf20Sopenharmony_ci	return 0;
2258c2ecf20Sopenharmony_ci}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_cistatic int auxtrace_queues__grow(struct auxtrace_queues *queues,
2288c2ecf20Sopenharmony_ci				 unsigned int new_nr_queues)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	unsigned int nr_queues = queues->nr_queues;
2318c2ecf20Sopenharmony_ci	struct auxtrace_queue *queue_array;
2328c2ecf20Sopenharmony_ci	unsigned int i;
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	if (!nr_queues)
2358c2ecf20Sopenharmony_ci		nr_queues = AUXTRACE_INIT_NR_QUEUES;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	while (nr_queues && nr_queues < new_nr_queues)
2388c2ecf20Sopenharmony_ci		nr_queues <<= 1;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues)
2418c2ecf20Sopenharmony_ci		return -EINVAL;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	queue_array = auxtrace_alloc_queue_array(nr_queues);
2448c2ecf20Sopenharmony_ci	if (!queue_array)
2458c2ecf20Sopenharmony_ci		return -ENOMEM;
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
2488c2ecf20Sopenharmony_ci		list_splice_tail(&queues->queue_array[i].head,
2498c2ecf20Sopenharmony_ci				 &queue_array[i].head);
2508c2ecf20Sopenharmony_ci		queue_array[i].tid = queues->queue_array[i].tid;
2518c2ecf20Sopenharmony_ci		queue_array[i].cpu = queues->queue_array[i].cpu;
2528c2ecf20Sopenharmony_ci		queue_array[i].set = queues->queue_array[i].set;
2538c2ecf20Sopenharmony_ci		queue_array[i].priv = queues->queue_array[i].priv;
2548c2ecf20Sopenharmony_ci	}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	queues->nr_queues = nr_queues;
2578c2ecf20Sopenharmony_ci	queues->queue_array = queue_array;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	return 0;
2608c2ecf20Sopenharmony_ci}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_cistatic void *auxtrace_copy_data(u64 size, struct perf_session *session)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	int fd = perf_data__fd(session->data);
2658c2ecf20Sopenharmony_ci	void *p;
2668c2ecf20Sopenharmony_ci	ssize_t ret;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (size > SSIZE_MAX)
2698c2ecf20Sopenharmony_ci		return NULL;
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	p = malloc(size);
2728c2ecf20Sopenharmony_ci	if (!p)
2738c2ecf20Sopenharmony_ci		return NULL;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci	ret = readn(fd, p, size);
2768c2ecf20Sopenharmony_ci	if (ret != (ssize_t)size) {
2778c2ecf20Sopenharmony_ci		free(p);
2788c2ecf20Sopenharmony_ci		return NULL;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	return p;
2828c2ecf20Sopenharmony_ci}
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_cistatic int auxtrace_queues__queue_buffer(struct auxtrace_queues *queues,
2858c2ecf20Sopenharmony_ci					 unsigned int idx,
2868c2ecf20Sopenharmony_ci					 struct auxtrace_buffer *buffer)
2878c2ecf20Sopenharmony_ci{
2888c2ecf20Sopenharmony_ci	struct auxtrace_queue *queue;
2898c2ecf20Sopenharmony_ci	int err;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	if (idx >= queues->nr_queues) {
2928c2ecf20Sopenharmony_ci		err = auxtrace_queues__grow(queues, idx + 1);
2938c2ecf20Sopenharmony_ci		if (err)
2948c2ecf20Sopenharmony_ci			return err;
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	queue = &queues->queue_array[idx];
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	if (!queue->set) {
3008c2ecf20Sopenharmony_ci		queue->set = true;
3018c2ecf20Sopenharmony_ci		queue->tid = buffer->tid;
3028c2ecf20Sopenharmony_ci		queue->cpu = buffer->cpu;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci	buffer->buffer_nr = queues->next_buffer_nr++;
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	list_add_tail(&buffer->list, &queue->head);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	queues->new_data = true;
3108c2ecf20Sopenharmony_ci	queues->populated = true;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	return 0;
3138c2ecf20Sopenharmony_ci}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci/* Limit buffers to 32MiB on 32-bit */
3168c2ecf20Sopenharmony_ci#define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024)
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic int auxtrace_queues__split_buffer(struct auxtrace_queues *queues,
3198c2ecf20Sopenharmony_ci					 unsigned int idx,
3208c2ecf20Sopenharmony_ci					 struct auxtrace_buffer *buffer)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	u64 sz = buffer->size;
3238c2ecf20Sopenharmony_ci	bool consecutive = false;
3248c2ecf20Sopenharmony_ci	struct auxtrace_buffer *b;
3258c2ecf20Sopenharmony_ci	int err;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	while (sz > BUFFER_LIMIT_FOR_32_BIT) {
3288c2ecf20Sopenharmony_ci		b = memdup(buffer, sizeof(struct auxtrace_buffer));
3298c2ecf20Sopenharmony_ci		if (!b)
3308c2ecf20Sopenharmony_ci			return -ENOMEM;
3318c2ecf20Sopenharmony_ci		b->size = BUFFER_LIMIT_FOR_32_BIT;
3328c2ecf20Sopenharmony_ci		b->consecutive = consecutive;
3338c2ecf20Sopenharmony_ci		err = auxtrace_queues__queue_buffer(queues, idx, b);
3348c2ecf20Sopenharmony_ci		if (err) {
3358c2ecf20Sopenharmony_ci			auxtrace_buffer__free(b);
3368c2ecf20Sopenharmony_ci			return err;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci		buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT;
3398c2ecf20Sopenharmony_ci		sz -= BUFFER_LIMIT_FOR_32_BIT;
3408c2ecf20Sopenharmony_ci		consecutive = true;
3418c2ecf20Sopenharmony_ci	}
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	buffer->size = sz;
3448c2ecf20Sopenharmony_ci	buffer->consecutive = consecutive;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	return 0;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic bool filter_cpu(struct perf_session *session, int cpu)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap;
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic int auxtrace_queues__add_buffer(struct auxtrace_queues *queues,
3578c2ecf20Sopenharmony_ci				       struct perf_session *session,
3588c2ecf20Sopenharmony_ci				       unsigned int idx,
3598c2ecf20Sopenharmony_ci				       struct auxtrace_buffer *buffer,
3608c2ecf20Sopenharmony_ci				       struct auxtrace_buffer **buffer_ptr)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	int err = -ENOMEM;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	if (filter_cpu(session, buffer->cpu))
3658c2ecf20Sopenharmony_ci		return 0;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	buffer = memdup(buffer, sizeof(*buffer));
3688c2ecf20Sopenharmony_ci	if (!buffer)
3698c2ecf20Sopenharmony_ci		return -ENOMEM;
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ci	if (session->one_mmap) {
3728c2ecf20Sopenharmony_ci		buffer->data = buffer->data_offset - session->one_mmap_offset +
3738c2ecf20Sopenharmony_ci			       session->one_mmap_addr;
3748c2ecf20Sopenharmony_ci	} else if (perf_data__is_pipe(session->data)) {
3758c2ecf20Sopenharmony_ci		buffer->data = auxtrace_copy_data(buffer->size, session);
3768c2ecf20Sopenharmony_ci		if (!buffer->data)
3778c2ecf20Sopenharmony_ci			goto out_free;
3788c2ecf20Sopenharmony_ci		buffer->data_needs_freeing = true;
3798c2ecf20Sopenharmony_ci	} else if (BITS_PER_LONG == 32 &&
3808c2ecf20Sopenharmony_ci		   buffer->size > BUFFER_LIMIT_FOR_32_BIT) {
3818c2ecf20Sopenharmony_ci		err = auxtrace_queues__split_buffer(queues, idx, buffer);
3828c2ecf20Sopenharmony_ci		if (err)
3838c2ecf20Sopenharmony_ci			goto out_free;
3848c2ecf20Sopenharmony_ci	}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci	err = auxtrace_queues__queue_buffer(queues, idx, buffer);
3878c2ecf20Sopenharmony_ci	if (err)
3888c2ecf20Sopenharmony_ci		goto out_free;
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_ci	/* FIXME: Doesn't work for split buffer */
3918c2ecf20Sopenharmony_ci	if (buffer_ptr)
3928c2ecf20Sopenharmony_ci		*buffer_ptr = buffer;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	return 0;
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ciout_free:
3978c2ecf20Sopenharmony_ci	auxtrace_buffer__free(buffer);
3988c2ecf20Sopenharmony_ci	return err;
3998c2ecf20Sopenharmony_ci}
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ciint auxtrace_queues__add_event(struct auxtrace_queues *queues,
4028c2ecf20Sopenharmony_ci			       struct perf_session *session,
4038c2ecf20Sopenharmony_ci			       union perf_event *event, off_t data_offset,
4048c2ecf20Sopenharmony_ci			       struct auxtrace_buffer **buffer_ptr)
4058c2ecf20Sopenharmony_ci{
4068c2ecf20Sopenharmony_ci	struct auxtrace_buffer buffer = {
4078c2ecf20Sopenharmony_ci		.pid = -1,
4088c2ecf20Sopenharmony_ci		.tid = event->auxtrace.tid,
4098c2ecf20Sopenharmony_ci		.cpu = event->auxtrace.cpu,
4108c2ecf20Sopenharmony_ci		.data_offset = data_offset,
4118c2ecf20Sopenharmony_ci		.offset = event->auxtrace.offset,
4128c2ecf20Sopenharmony_ci		.reference = event->auxtrace.reference,
4138c2ecf20Sopenharmony_ci		.size = event->auxtrace.size,
4148c2ecf20Sopenharmony_ci	};
4158c2ecf20Sopenharmony_ci	unsigned int idx = event->auxtrace.idx;
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	return auxtrace_queues__add_buffer(queues, session, idx, &buffer,
4188c2ecf20Sopenharmony_ci					   buffer_ptr);
4198c2ecf20Sopenharmony_ci}
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues,
4228c2ecf20Sopenharmony_ci					      struct perf_session *session,
4238c2ecf20Sopenharmony_ci					      off_t file_offset, size_t sz)
4248c2ecf20Sopenharmony_ci{
4258c2ecf20Sopenharmony_ci	union perf_event *event;
4268c2ecf20Sopenharmony_ci	int err;
4278c2ecf20Sopenharmony_ci	char buf[PERF_SAMPLE_MAX_SIZE];
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	err = perf_session__peek_event(session, file_offset, buf,
4308c2ecf20Sopenharmony_ci				       PERF_SAMPLE_MAX_SIZE, &event, NULL);
4318c2ecf20Sopenharmony_ci	if (err)
4328c2ecf20Sopenharmony_ci		return err;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	if (event->header.type == PERF_RECORD_AUXTRACE) {
4358c2ecf20Sopenharmony_ci		if (event->header.size < sizeof(struct perf_record_auxtrace) ||
4368c2ecf20Sopenharmony_ci		    event->header.size != sz) {
4378c2ecf20Sopenharmony_ci			err = -EINVAL;
4388c2ecf20Sopenharmony_ci			goto out;
4398c2ecf20Sopenharmony_ci		}
4408c2ecf20Sopenharmony_ci		file_offset += event->header.size;
4418c2ecf20Sopenharmony_ci		err = auxtrace_queues__add_event(queues, session, event,
4428c2ecf20Sopenharmony_ci						 file_offset, NULL);
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ciout:
4458c2ecf20Sopenharmony_ci	return err;
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_civoid auxtrace_queues__free(struct auxtrace_queues *queues)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	unsigned int i;
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	for (i = 0; i < queues->nr_queues; i++) {
4538c2ecf20Sopenharmony_ci		while (!list_empty(&queues->queue_array[i].head)) {
4548c2ecf20Sopenharmony_ci			struct auxtrace_buffer *buffer;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci			buffer = list_entry(queues->queue_array[i].head.next,
4578c2ecf20Sopenharmony_ci					    struct auxtrace_buffer, list);
4588c2ecf20Sopenharmony_ci			list_del_init(&buffer->list);
4598c2ecf20Sopenharmony_ci			auxtrace_buffer__free(buffer);
4608c2ecf20Sopenharmony_ci		}
4618c2ecf20Sopenharmony_ci	}
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	zfree(&queues->queue_array);
4648c2ecf20Sopenharmony_ci	queues->nr_queues = 0;
4658c2ecf20Sopenharmony_ci}
4668c2ecf20Sopenharmony_ci
4678c2ecf20Sopenharmony_cistatic void auxtrace_heapify(struct auxtrace_heap_item *heap_array,
4688c2ecf20Sopenharmony_ci			     unsigned int pos, unsigned int queue_nr,
4698c2ecf20Sopenharmony_ci			     u64 ordinal)
4708c2ecf20Sopenharmony_ci{
4718c2ecf20Sopenharmony_ci	unsigned int parent;
4728c2ecf20Sopenharmony_ci
4738c2ecf20Sopenharmony_ci	while (pos) {
4748c2ecf20Sopenharmony_ci		parent = (pos - 1) >> 1;
4758c2ecf20Sopenharmony_ci		if (heap_array[parent].ordinal <= ordinal)
4768c2ecf20Sopenharmony_ci			break;
4778c2ecf20Sopenharmony_ci		heap_array[pos] = heap_array[parent];
4788c2ecf20Sopenharmony_ci		pos = parent;
4798c2ecf20Sopenharmony_ci	}
4808c2ecf20Sopenharmony_ci	heap_array[pos].queue_nr = queue_nr;
4818c2ecf20Sopenharmony_ci	heap_array[pos].ordinal = ordinal;
4828c2ecf20Sopenharmony_ci}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ciint auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr,
4858c2ecf20Sopenharmony_ci		       u64 ordinal)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	struct auxtrace_heap_item *heap_array;
4888c2ecf20Sopenharmony_ci
4898c2ecf20Sopenharmony_ci	if (queue_nr >= heap->heap_sz) {
4908c2ecf20Sopenharmony_ci		unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		while (heap_sz <= queue_nr)
4938c2ecf20Sopenharmony_ci			heap_sz <<= 1;
4948c2ecf20Sopenharmony_ci		heap_array = realloc(heap->heap_array,
4958c2ecf20Sopenharmony_ci				     heap_sz * sizeof(struct auxtrace_heap_item));
4968c2ecf20Sopenharmony_ci		if (!heap_array)
4978c2ecf20Sopenharmony_ci			return -ENOMEM;
4988c2ecf20Sopenharmony_ci		heap->heap_array = heap_array;
4998c2ecf20Sopenharmony_ci		heap->heap_sz = heap_sz;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	auxtrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal);
5038c2ecf20Sopenharmony_ci
5048c2ecf20Sopenharmony_ci	return 0;
5058c2ecf20Sopenharmony_ci}
5068c2ecf20Sopenharmony_ci
5078c2ecf20Sopenharmony_civoid auxtrace_heap__free(struct auxtrace_heap *heap)
5088c2ecf20Sopenharmony_ci{
5098c2ecf20Sopenharmony_ci	zfree(&heap->heap_array);
5108c2ecf20Sopenharmony_ci	heap->heap_cnt = 0;
5118c2ecf20Sopenharmony_ci	heap->heap_sz = 0;
5128c2ecf20Sopenharmony_ci}
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_civoid auxtrace_heap__pop(struct auxtrace_heap *heap)
5158c2ecf20Sopenharmony_ci{
5168c2ecf20Sopenharmony_ci	unsigned int pos, last, heap_cnt = heap->heap_cnt;
5178c2ecf20Sopenharmony_ci	struct auxtrace_heap_item *heap_array;
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	if (!heap_cnt)
5208c2ecf20Sopenharmony_ci		return;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	heap->heap_cnt -= 1;
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	heap_array = heap->heap_array;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	pos = 0;
5278c2ecf20Sopenharmony_ci	while (1) {
5288c2ecf20Sopenharmony_ci		unsigned int left, right;
5298c2ecf20Sopenharmony_ci
5308c2ecf20Sopenharmony_ci		left = (pos << 1) + 1;
5318c2ecf20Sopenharmony_ci		if (left >= heap_cnt)
5328c2ecf20Sopenharmony_ci			break;
5338c2ecf20Sopenharmony_ci		right = left + 1;
5348c2ecf20Sopenharmony_ci		if (right >= heap_cnt) {
5358c2ecf20Sopenharmony_ci			heap_array[pos] = heap_array[left];
5368c2ecf20Sopenharmony_ci			return;
5378c2ecf20Sopenharmony_ci		}
5388c2ecf20Sopenharmony_ci		if (heap_array[left].ordinal < heap_array[right].ordinal) {
5398c2ecf20Sopenharmony_ci			heap_array[pos] = heap_array[left];
5408c2ecf20Sopenharmony_ci			pos = left;
5418c2ecf20Sopenharmony_ci		} else {
5428c2ecf20Sopenharmony_ci			heap_array[pos] = heap_array[right];
5438c2ecf20Sopenharmony_ci			pos = right;
5448c2ecf20Sopenharmony_ci		}
5458c2ecf20Sopenharmony_ci	}
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	last = heap_cnt - 1;
5488c2ecf20Sopenharmony_ci	auxtrace_heapify(heap_array, pos, heap_array[last].queue_nr,
5498c2ecf20Sopenharmony_ci			 heap_array[last].ordinal);
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cisize_t auxtrace_record__info_priv_size(struct auxtrace_record *itr,
5538c2ecf20Sopenharmony_ci				       struct evlist *evlist)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	if (itr)
5568c2ecf20Sopenharmony_ci		return itr->info_priv_size(itr, evlist);
5578c2ecf20Sopenharmony_ci	return 0;
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ci
5608c2ecf20Sopenharmony_cistatic int auxtrace_not_supported(void)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	pr_err("AUX area tracing is not supported on this architecture\n");
5638c2ecf20Sopenharmony_ci	return -EINVAL;
5648c2ecf20Sopenharmony_ci}
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ciint auxtrace_record__info_fill(struct auxtrace_record *itr,
5678c2ecf20Sopenharmony_ci			       struct perf_session *session,
5688c2ecf20Sopenharmony_ci			       struct perf_record_auxtrace_info *auxtrace_info,
5698c2ecf20Sopenharmony_ci			       size_t priv_size)
5708c2ecf20Sopenharmony_ci{
5718c2ecf20Sopenharmony_ci	if (itr)
5728c2ecf20Sopenharmony_ci		return itr->info_fill(itr, session, auxtrace_info, priv_size);
5738c2ecf20Sopenharmony_ci	return auxtrace_not_supported();
5748c2ecf20Sopenharmony_ci}
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_civoid auxtrace_record__free(struct auxtrace_record *itr)
5778c2ecf20Sopenharmony_ci{
5788c2ecf20Sopenharmony_ci	if (itr)
5798c2ecf20Sopenharmony_ci		itr->free(itr);
5808c2ecf20Sopenharmony_ci}
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ciint auxtrace_record__snapshot_start(struct auxtrace_record *itr)
5838c2ecf20Sopenharmony_ci{
5848c2ecf20Sopenharmony_ci	if (itr && itr->snapshot_start)
5858c2ecf20Sopenharmony_ci		return itr->snapshot_start(itr);
5868c2ecf20Sopenharmony_ci	return 0;
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_ciint auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit)
5908c2ecf20Sopenharmony_ci{
5918c2ecf20Sopenharmony_ci	if (!on_exit && itr && itr->snapshot_finish)
5928c2ecf20Sopenharmony_ci		return itr->snapshot_finish(itr);
5938c2ecf20Sopenharmony_ci	return 0;
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_ciint auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx,
5978c2ecf20Sopenharmony_ci				   struct auxtrace_mmap *mm,
5988c2ecf20Sopenharmony_ci				   unsigned char *data, u64 *head, u64 *old)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	if (itr && itr->find_snapshot)
6018c2ecf20Sopenharmony_ci		return itr->find_snapshot(itr, idx, mm, data, head, old);
6028c2ecf20Sopenharmony_ci	return 0;
6038c2ecf20Sopenharmony_ci}
6048c2ecf20Sopenharmony_ci
6058c2ecf20Sopenharmony_ciint auxtrace_record__options(struct auxtrace_record *itr,
6068c2ecf20Sopenharmony_ci			     struct evlist *evlist,
6078c2ecf20Sopenharmony_ci			     struct record_opts *opts)
6088c2ecf20Sopenharmony_ci{
6098c2ecf20Sopenharmony_ci	if (itr) {
6108c2ecf20Sopenharmony_ci		itr->evlist = evlist;
6118c2ecf20Sopenharmony_ci		return itr->recording_options(itr, evlist, opts);
6128c2ecf20Sopenharmony_ci	}
6138c2ecf20Sopenharmony_ci	return 0;
6148c2ecf20Sopenharmony_ci}
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ciu64 auxtrace_record__reference(struct auxtrace_record *itr)
6178c2ecf20Sopenharmony_ci{
6188c2ecf20Sopenharmony_ci	if (itr)
6198c2ecf20Sopenharmony_ci		return itr->reference(itr);
6208c2ecf20Sopenharmony_ci	return 0;
6218c2ecf20Sopenharmony_ci}
6228c2ecf20Sopenharmony_ci
6238c2ecf20Sopenharmony_ciint auxtrace_parse_snapshot_options(struct auxtrace_record *itr,
6248c2ecf20Sopenharmony_ci				    struct record_opts *opts, const char *str)
6258c2ecf20Sopenharmony_ci{
6268c2ecf20Sopenharmony_ci	if (!str)
6278c2ecf20Sopenharmony_ci		return 0;
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ci	/* PMU-agnostic options */
6308c2ecf20Sopenharmony_ci	switch (*str) {
6318c2ecf20Sopenharmony_ci	case 'e':
6328c2ecf20Sopenharmony_ci		opts->auxtrace_snapshot_on_exit = true;
6338c2ecf20Sopenharmony_ci		str++;
6348c2ecf20Sopenharmony_ci		break;
6358c2ecf20Sopenharmony_ci	default:
6368c2ecf20Sopenharmony_ci		break;
6378c2ecf20Sopenharmony_ci	}
6388c2ecf20Sopenharmony_ci
6398c2ecf20Sopenharmony_ci	if (itr && itr->parse_snapshot_options)
6408c2ecf20Sopenharmony_ci		return itr->parse_snapshot_options(itr, opts, str);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci	pr_err("No AUX area tracing to snapshot\n");
6438c2ecf20Sopenharmony_ci	return -EINVAL;
6448c2ecf20Sopenharmony_ci}
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ciint auxtrace_record__read_finish(struct auxtrace_record *itr, int idx)
6478c2ecf20Sopenharmony_ci{
6488c2ecf20Sopenharmony_ci	struct evsel *evsel;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (!itr->evlist || !itr->pmu)
6518c2ecf20Sopenharmony_ci		return -EINVAL;
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	evlist__for_each_entry(itr->evlist, evsel) {
6548c2ecf20Sopenharmony_ci		if (evsel->core.attr.type == itr->pmu->type) {
6558c2ecf20Sopenharmony_ci			if (evsel->disabled)
6568c2ecf20Sopenharmony_ci				return 0;
6578c2ecf20Sopenharmony_ci			return perf_evlist__enable_event_idx(itr->evlist, evsel,
6588c2ecf20Sopenharmony_ci							     idx);
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci	return -EINVAL;
6628c2ecf20Sopenharmony_ci}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci/*
6658c2ecf20Sopenharmony_ci * Event record size is 16-bit which results in a maximum size of about 64KiB.
6668c2ecf20Sopenharmony_ci * Allow about 4KiB for the rest of the sample record, to give a maximum
6678c2ecf20Sopenharmony_ci * AUX area sample size of 60KiB.
6688c2ecf20Sopenharmony_ci */
6698c2ecf20Sopenharmony_ci#define MAX_AUX_SAMPLE_SIZE (60 * 1024)
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci/* Arbitrary default size if no other default provided */
6728c2ecf20Sopenharmony_ci#define DEFAULT_AUX_SAMPLE_SIZE (4 * 1024)
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_cistatic int auxtrace_validate_aux_sample_size(struct evlist *evlist,
6758c2ecf20Sopenharmony_ci					     struct record_opts *opts)
6768c2ecf20Sopenharmony_ci{
6778c2ecf20Sopenharmony_ci	struct evsel *evsel;
6788c2ecf20Sopenharmony_ci	bool has_aux_leader = false;
6798c2ecf20Sopenharmony_ci	u32 sz;
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
6828c2ecf20Sopenharmony_ci		sz = evsel->core.attr.aux_sample_size;
6838c2ecf20Sopenharmony_ci		if (evsel__is_group_leader(evsel)) {
6848c2ecf20Sopenharmony_ci			has_aux_leader = evsel__is_aux_event(evsel);
6858c2ecf20Sopenharmony_ci			if (sz) {
6868c2ecf20Sopenharmony_ci				if (has_aux_leader)
6878c2ecf20Sopenharmony_ci					pr_err("Cannot add AUX area sampling to an AUX area event\n");
6888c2ecf20Sopenharmony_ci				else
6898c2ecf20Sopenharmony_ci					pr_err("Cannot add AUX area sampling to a group leader\n");
6908c2ecf20Sopenharmony_ci				return -EINVAL;
6918c2ecf20Sopenharmony_ci			}
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci		if (sz > MAX_AUX_SAMPLE_SIZE) {
6948c2ecf20Sopenharmony_ci			pr_err("AUX area sample size %u too big, max. %d\n",
6958c2ecf20Sopenharmony_ci			       sz, MAX_AUX_SAMPLE_SIZE);
6968c2ecf20Sopenharmony_ci			return -EINVAL;
6978c2ecf20Sopenharmony_ci		}
6988c2ecf20Sopenharmony_ci		if (sz) {
6998c2ecf20Sopenharmony_ci			if (!has_aux_leader) {
7008c2ecf20Sopenharmony_ci				pr_err("Cannot add AUX area sampling because group leader is not an AUX area event\n");
7018c2ecf20Sopenharmony_ci				return -EINVAL;
7028c2ecf20Sopenharmony_ci			}
7038c2ecf20Sopenharmony_ci			evsel__set_sample_bit(evsel, AUX);
7048c2ecf20Sopenharmony_ci			opts->auxtrace_sample_mode = true;
7058c2ecf20Sopenharmony_ci		} else {
7068c2ecf20Sopenharmony_ci			evsel__reset_sample_bit(evsel, AUX);
7078c2ecf20Sopenharmony_ci		}
7088c2ecf20Sopenharmony_ci	}
7098c2ecf20Sopenharmony_ci
7108c2ecf20Sopenharmony_ci	if (!opts->auxtrace_sample_mode) {
7118c2ecf20Sopenharmony_ci		pr_err("AUX area sampling requires an AUX area event group leader plus other events to which to add samples\n");
7128c2ecf20Sopenharmony_ci		return -EINVAL;
7138c2ecf20Sopenharmony_ci	}
7148c2ecf20Sopenharmony_ci
7158c2ecf20Sopenharmony_ci	if (!perf_can_aux_sample()) {
7168c2ecf20Sopenharmony_ci		pr_err("AUX area sampling is not supported by kernel\n");
7178c2ecf20Sopenharmony_ci		return -EINVAL;
7188c2ecf20Sopenharmony_ci	}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ci	return 0;
7218c2ecf20Sopenharmony_ci}
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ciint auxtrace_parse_sample_options(struct auxtrace_record *itr,
7248c2ecf20Sopenharmony_ci				  struct evlist *evlist,
7258c2ecf20Sopenharmony_ci				  struct record_opts *opts, const char *str)
7268c2ecf20Sopenharmony_ci{
7278c2ecf20Sopenharmony_ci	struct evsel_config_term *term;
7288c2ecf20Sopenharmony_ci	struct evsel *aux_evsel;
7298c2ecf20Sopenharmony_ci	bool has_aux_sample_size = false;
7308c2ecf20Sopenharmony_ci	bool has_aux_leader = false;
7318c2ecf20Sopenharmony_ci	struct evsel *evsel;
7328c2ecf20Sopenharmony_ci	char *endptr;
7338c2ecf20Sopenharmony_ci	unsigned long sz;
7348c2ecf20Sopenharmony_ci
7358c2ecf20Sopenharmony_ci	if (!str)
7368c2ecf20Sopenharmony_ci		goto no_opt;
7378c2ecf20Sopenharmony_ci
7388c2ecf20Sopenharmony_ci	if (!itr) {
7398c2ecf20Sopenharmony_ci		pr_err("No AUX area event to sample\n");
7408c2ecf20Sopenharmony_ci		return -EINVAL;
7418c2ecf20Sopenharmony_ci	}
7428c2ecf20Sopenharmony_ci
7438c2ecf20Sopenharmony_ci	sz = strtoul(str, &endptr, 0);
7448c2ecf20Sopenharmony_ci	if (*endptr || sz > UINT_MAX) {
7458c2ecf20Sopenharmony_ci		pr_err("Bad AUX area sampling option: '%s'\n", str);
7468c2ecf20Sopenharmony_ci		return -EINVAL;
7478c2ecf20Sopenharmony_ci	}
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	if (!sz)
7508c2ecf20Sopenharmony_ci		sz = itr->default_aux_sample_size;
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	if (!sz)
7538c2ecf20Sopenharmony_ci		sz = DEFAULT_AUX_SAMPLE_SIZE;
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_ci	/* Set aux_sample_size based on --aux-sample option */
7568c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
7578c2ecf20Sopenharmony_ci		if (evsel__is_group_leader(evsel)) {
7588c2ecf20Sopenharmony_ci			has_aux_leader = evsel__is_aux_event(evsel);
7598c2ecf20Sopenharmony_ci		} else if (has_aux_leader) {
7608c2ecf20Sopenharmony_ci			evsel->core.attr.aux_sample_size = sz;
7618c2ecf20Sopenharmony_ci		}
7628c2ecf20Sopenharmony_ci	}
7638c2ecf20Sopenharmony_cino_opt:
7648c2ecf20Sopenharmony_ci	aux_evsel = NULL;
7658c2ecf20Sopenharmony_ci	/* Override with aux_sample_size from config term */
7668c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
7678c2ecf20Sopenharmony_ci		if (evsel__is_aux_event(evsel))
7688c2ecf20Sopenharmony_ci			aux_evsel = evsel;
7698c2ecf20Sopenharmony_ci		term = evsel__get_config_term(evsel, AUX_SAMPLE_SIZE);
7708c2ecf20Sopenharmony_ci		if (term) {
7718c2ecf20Sopenharmony_ci			has_aux_sample_size = true;
7728c2ecf20Sopenharmony_ci			evsel->core.attr.aux_sample_size = term->val.aux_sample_size;
7738c2ecf20Sopenharmony_ci			/* If possible, group with the AUX event */
7748c2ecf20Sopenharmony_ci			if (aux_evsel && evsel->core.attr.aux_sample_size)
7758c2ecf20Sopenharmony_ci				perf_evlist__regroup(evlist, aux_evsel, evsel);
7768c2ecf20Sopenharmony_ci		}
7778c2ecf20Sopenharmony_ci	}
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	if (!str && !has_aux_sample_size)
7808c2ecf20Sopenharmony_ci		return 0;
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_ci	if (!itr) {
7838c2ecf20Sopenharmony_ci		pr_err("No AUX area event to sample\n");
7848c2ecf20Sopenharmony_ci		return -EINVAL;
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	return auxtrace_validate_aux_sample_size(evlist, opts);
7888c2ecf20Sopenharmony_ci}
7898c2ecf20Sopenharmony_ci
7908c2ecf20Sopenharmony_cistruct auxtrace_record *__weak
7918c2ecf20Sopenharmony_ciauxtrace_record__init(struct evlist *evlist __maybe_unused, int *err)
7928c2ecf20Sopenharmony_ci{
7938c2ecf20Sopenharmony_ci	*err = 0;
7948c2ecf20Sopenharmony_ci	return NULL;
7958c2ecf20Sopenharmony_ci}
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_cistatic int auxtrace_index__alloc(struct list_head *head)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index;
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	auxtrace_index = malloc(sizeof(struct auxtrace_index));
8028c2ecf20Sopenharmony_ci	if (!auxtrace_index)
8038c2ecf20Sopenharmony_ci		return -ENOMEM;
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	auxtrace_index->nr = 0;
8068c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&auxtrace_index->list);
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci	list_add_tail(&auxtrace_index->list, head);
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	return 0;
8118c2ecf20Sopenharmony_ci}
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_civoid auxtrace_index__free(struct list_head *head)
8148c2ecf20Sopenharmony_ci{
8158c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index, *n;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	list_for_each_entry_safe(auxtrace_index, n, head, list) {
8188c2ecf20Sopenharmony_ci		list_del_init(&auxtrace_index->list);
8198c2ecf20Sopenharmony_ci		free(auxtrace_index);
8208c2ecf20Sopenharmony_ci	}
8218c2ecf20Sopenharmony_ci}
8228c2ecf20Sopenharmony_ci
8238c2ecf20Sopenharmony_cistatic struct auxtrace_index *auxtrace_index__last(struct list_head *head)
8248c2ecf20Sopenharmony_ci{
8258c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index;
8268c2ecf20Sopenharmony_ci	int err;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	if (list_empty(head)) {
8298c2ecf20Sopenharmony_ci		err = auxtrace_index__alloc(head);
8308c2ecf20Sopenharmony_ci		if (err)
8318c2ecf20Sopenharmony_ci			return NULL;
8328c2ecf20Sopenharmony_ci	}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	auxtrace_index = list_entry(head->prev, struct auxtrace_index, list);
8358c2ecf20Sopenharmony_ci
8368c2ecf20Sopenharmony_ci	if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) {
8378c2ecf20Sopenharmony_ci		err = auxtrace_index__alloc(head);
8388c2ecf20Sopenharmony_ci		if (err)
8398c2ecf20Sopenharmony_ci			return NULL;
8408c2ecf20Sopenharmony_ci		auxtrace_index = list_entry(head->prev, struct auxtrace_index,
8418c2ecf20Sopenharmony_ci					    list);
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	return auxtrace_index;
8458c2ecf20Sopenharmony_ci}
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ciint auxtrace_index__auxtrace_event(struct list_head *head,
8488c2ecf20Sopenharmony_ci				   union perf_event *event, off_t file_offset)
8498c2ecf20Sopenharmony_ci{
8508c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index;
8518c2ecf20Sopenharmony_ci	size_t nr;
8528c2ecf20Sopenharmony_ci
8538c2ecf20Sopenharmony_ci	auxtrace_index = auxtrace_index__last(head);
8548c2ecf20Sopenharmony_ci	if (!auxtrace_index)
8558c2ecf20Sopenharmony_ci		return -ENOMEM;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci	nr = auxtrace_index->nr;
8588c2ecf20Sopenharmony_ci	auxtrace_index->entries[nr].file_offset = file_offset;
8598c2ecf20Sopenharmony_ci	auxtrace_index->entries[nr].sz = event->header.size;
8608c2ecf20Sopenharmony_ci	auxtrace_index->nr += 1;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci	return 0;
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_cistatic int auxtrace_index__do_write(int fd,
8668c2ecf20Sopenharmony_ci				    struct auxtrace_index *auxtrace_index)
8678c2ecf20Sopenharmony_ci{
8688c2ecf20Sopenharmony_ci	struct auxtrace_index_entry ent;
8698c2ecf20Sopenharmony_ci	size_t i;
8708c2ecf20Sopenharmony_ci
8718c2ecf20Sopenharmony_ci	for (i = 0; i < auxtrace_index->nr; i++) {
8728c2ecf20Sopenharmony_ci		ent.file_offset = auxtrace_index->entries[i].file_offset;
8738c2ecf20Sopenharmony_ci		ent.sz = auxtrace_index->entries[i].sz;
8748c2ecf20Sopenharmony_ci		if (writen(fd, &ent, sizeof(ent)) != sizeof(ent))
8758c2ecf20Sopenharmony_ci			return -errno;
8768c2ecf20Sopenharmony_ci	}
8778c2ecf20Sopenharmony_ci	return 0;
8788c2ecf20Sopenharmony_ci}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ciint auxtrace_index__write(int fd, struct list_head *head)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index;
8838c2ecf20Sopenharmony_ci	u64 total = 0;
8848c2ecf20Sopenharmony_ci	int err;
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_ci	list_for_each_entry(auxtrace_index, head, list)
8878c2ecf20Sopenharmony_ci		total += auxtrace_index->nr;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (writen(fd, &total, sizeof(total)) != sizeof(total))
8908c2ecf20Sopenharmony_ci		return -errno;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	list_for_each_entry(auxtrace_index, head, list) {
8938c2ecf20Sopenharmony_ci		err = auxtrace_index__do_write(fd, auxtrace_index);
8948c2ecf20Sopenharmony_ci		if (err)
8958c2ecf20Sopenharmony_ci			return err;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	return 0;
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_cistatic int auxtrace_index__process_entry(int fd, struct list_head *head,
9028c2ecf20Sopenharmony_ci					 bool needs_swap)
9038c2ecf20Sopenharmony_ci{
9048c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index;
9058c2ecf20Sopenharmony_ci	struct auxtrace_index_entry ent;
9068c2ecf20Sopenharmony_ci	size_t nr;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	if (readn(fd, &ent, sizeof(ent)) != sizeof(ent))
9098c2ecf20Sopenharmony_ci		return -1;
9108c2ecf20Sopenharmony_ci
9118c2ecf20Sopenharmony_ci	auxtrace_index = auxtrace_index__last(head);
9128c2ecf20Sopenharmony_ci	if (!auxtrace_index)
9138c2ecf20Sopenharmony_ci		return -1;
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	nr = auxtrace_index->nr;
9168c2ecf20Sopenharmony_ci	if (needs_swap) {
9178c2ecf20Sopenharmony_ci		auxtrace_index->entries[nr].file_offset =
9188c2ecf20Sopenharmony_ci						bswap_64(ent.file_offset);
9198c2ecf20Sopenharmony_ci		auxtrace_index->entries[nr].sz = bswap_64(ent.sz);
9208c2ecf20Sopenharmony_ci	} else {
9218c2ecf20Sopenharmony_ci		auxtrace_index->entries[nr].file_offset = ent.file_offset;
9228c2ecf20Sopenharmony_ci		auxtrace_index->entries[nr].sz = ent.sz;
9238c2ecf20Sopenharmony_ci	}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_ci	auxtrace_index->nr = nr + 1;
9268c2ecf20Sopenharmony_ci
9278c2ecf20Sopenharmony_ci	return 0;
9288c2ecf20Sopenharmony_ci}
9298c2ecf20Sopenharmony_ci
9308c2ecf20Sopenharmony_ciint auxtrace_index__process(int fd, u64 size, struct perf_session *session,
9318c2ecf20Sopenharmony_ci			    bool needs_swap)
9328c2ecf20Sopenharmony_ci{
9338c2ecf20Sopenharmony_ci	struct list_head *head = &session->auxtrace_index;
9348c2ecf20Sopenharmony_ci	u64 nr;
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (readn(fd, &nr, sizeof(u64)) != sizeof(u64))
9378c2ecf20Sopenharmony_ci		return -1;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	if (needs_swap)
9408c2ecf20Sopenharmony_ci		nr = bswap_64(nr);
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_ci	if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size)
9438c2ecf20Sopenharmony_ci		return -1;
9448c2ecf20Sopenharmony_ci
9458c2ecf20Sopenharmony_ci	while (nr--) {
9468c2ecf20Sopenharmony_ci		int err;
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci		err = auxtrace_index__process_entry(fd, head, needs_swap);
9498c2ecf20Sopenharmony_ci		if (err)
9508c2ecf20Sopenharmony_ci			return -1;
9518c2ecf20Sopenharmony_ci	}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	return 0;
9548c2ecf20Sopenharmony_ci}
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_cistatic int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues,
9578c2ecf20Sopenharmony_ci						struct perf_session *session,
9588c2ecf20Sopenharmony_ci						struct auxtrace_index_entry *ent)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	return auxtrace_queues__add_indexed_event(queues, session,
9618c2ecf20Sopenharmony_ci						  ent->file_offset, ent->sz);
9628c2ecf20Sopenharmony_ci}
9638c2ecf20Sopenharmony_ci
9648c2ecf20Sopenharmony_ciint auxtrace_queues__process_index(struct auxtrace_queues *queues,
9658c2ecf20Sopenharmony_ci				   struct perf_session *session)
9668c2ecf20Sopenharmony_ci{
9678c2ecf20Sopenharmony_ci	struct auxtrace_index *auxtrace_index;
9688c2ecf20Sopenharmony_ci	struct auxtrace_index_entry *ent;
9698c2ecf20Sopenharmony_ci	size_t i;
9708c2ecf20Sopenharmony_ci	int err;
9718c2ecf20Sopenharmony_ci
9728c2ecf20Sopenharmony_ci	if (auxtrace__dont_decode(session))
9738c2ecf20Sopenharmony_ci		return 0;
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) {
9768c2ecf20Sopenharmony_ci		for (i = 0; i < auxtrace_index->nr; i++) {
9778c2ecf20Sopenharmony_ci			ent = &auxtrace_index->entries[i];
9788c2ecf20Sopenharmony_ci			err = auxtrace_queues__process_index_entry(queues,
9798c2ecf20Sopenharmony_ci								   session,
9808c2ecf20Sopenharmony_ci								   ent);
9818c2ecf20Sopenharmony_ci			if (err)
9828c2ecf20Sopenharmony_ci				return err;
9838c2ecf20Sopenharmony_ci		}
9848c2ecf20Sopenharmony_ci	}
9858c2ecf20Sopenharmony_ci	return 0;
9868c2ecf20Sopenharmony_ci}
9878c2ecf20Sopenharmony_ci
9888c2ecf20Sopenharmony_cistruct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue,
9898c2ecf20Sopenharmony_ci					      struct auxtrace_buffer *buffer)
9908c2ecf20Sopenharmony_ci{
9918c2ecf20Sopenharmony_ci	if (buffer) {
9928c2ecf20Sopenharmony_ci		if (list_is_last(&buffer->list, &queue->head))
9938c2ecf20Sopenharmony_ci			return NULL;
9948c2ecf20Sopenharmony_ci		return list_entry(buffer->list.next, struct auxtrace_buffer,
9958c2ecf20Sopenharmony_ci				  list);
9968c2ecf20Sopenharmony_ci	} else {
9978c2ecf20Sopenharmony_ci		if (list_empty(&queue->head))
9988c2ecf20Sopenharmony_ci			return NULL;
9998c2ecf20Sopenharmony_ci		return list_entry(queue->head.next, struct auxtrace_buffer,
10008c2ecf20Sopenharmony_ci				  list);
10018c2ecf20Sopenharmony_ci	}
10028c2ecf20Sopenharmony_ci}
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_cistruct auxtrace_queue *auxtrace_queues__sample_queue(struct auxtrace_queues *queues,
10058c2ecf20Sopenharmony_ci						     struct perf_sample *sample,
10068c2ecf20Sopenharmony_ci						     struct perf_session *session)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct perf_sample_id *sid;
10098c2ecf20Sopenharmony_ci	unsigned int idx;
10108c2ecf20Sopenharmony_ci	u64 id;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	id = sample->id;
10138c2ecf20Sopenharmony_ci	if (!id)
10148c2ecf20Sopenharmony_ci		return NULL;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	sid = perf_evlist__id2sid(session->evlist, id);
10178c2ecf20Sopenharmony_ci	if (!sid)
10188c2ecf20Sopenharmony_ci		return NULL;
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci	idx = sid->idx;
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_ci	if (idx >= queues->nr_queues)
10238c2ecf20Sopenharmony_ci		return NULL;
10248c2ecf20Sopenharmony_ci
10258c2ecf20Sopenharmony_ci	return &queues->queue_array[idx];
10268c2ecf20Sopenharmony_ci}
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ciint auxtrace_queues__add_sample(struct auxtrace_queues *queues,
10298c2ecf20Sopenharmony_ci				struct perf_session *session,
10308c2ecf20Sopenharmony_ci				struct perf_sample *sample, u64 data_offset,
10318c2ecf20Sopenharmony_ci				u64 reference)
10328c2ecf20Sopenharmony_ci{
10338c2ecf20Sopenharmony_ci	struct auxtrace_buffer buffer = {
10348c2ecf20Sopenharmony_ci		.pid = -1,
10358c2ecf20Sopenharmony_ci		.data_offset = data_offset,
10368c2ecf20Sopenharmony_ci		.reference = reference,
10378c2ecf20Sopenharmony_ci		.size = sample->aux_sample.size,
10388c2ecf20Sopenharmony_ci	};
10398c2ecf20Sopenharmony_ci	struct perf_sample_id *sid;
10408c2ecf20Sopenharmony_ci	u64 id = sample->id;
10418c2ecf20Sopenharmony_ci	unsigned int idx;
10428c2ecf20Sopenharmony_ci
10438c2ecf20Sopenharmony_ci	if (!id)
10448c2ecf20Sopenharmony_ci		return -EINVAL;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	sid = perf_evlist__id2sid(session->evlist, id);
10478c2ecf20Sopenharmony_ci	if (!sid)
10488c2ecf20Sopenharmony_ci		return -ENOENT;
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	idx = sid->idx;
10518c2ecf20Sopenharmony_ci	buffer.tid = sid->tid;
10528c2ecf20Sopenharmony_ci	buffer.cpu = sid->cpu;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	return auxtrace_queues__add_buffer(queues, session, idx, &buffer, NULL);
10558c2ecf20Sopenharmony_ci}
10568c2ecf20Sopenharmony_ci
10578c2ecf20Sopenharmony_cistruct queue_data {
10588c2ecf20Sopenharmony_ci	bool samples;
10598c2ecf20Sopenharmony_ci	bool events;
10608c2ecf20Sopenharmony_ci};
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_cistatic int auxtrace_queue_data_cb(struct perf_session *session,
10638c2ecf20Sopenharmony_ci				  union perf_event *event, u64 offset,
10648c2ecf20Sopenharmony_ci				  void *data)
10658c2ecf20Sopenharmony_ci{
10668c2ecf20Sopenharmony_ci	struct queue_data *qd = data;
10678c2ecf20Sopenharmony_ci	struct perf_sample sample;
10688c2ecf20Sopenharmony_ci	int err;
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	if (qd->events && event->header.type == PERF_RECORD_AUXTRACE) {
10718c2ecf20Sopenharmony_ci		if (event->header.size < sizeof(struct perf_record_auxtrace))
10728c2ecf20Sopenharmony_ci			return -EINVAL;
10738c2ecf20Sopenharmony_ci		offset += event->header.size;
10748c2ecf20Sopenharmony_ci		return session->auxtrace->queue_data(session, NULL, event,
10758c2ecf20Sopenharmony_ci						     offset);
10768c2ecf20Sopenharmony_ci	}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci	if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE)
10798c2ecf20Sopenharmony_ci		return 0;
10808c2ecf20Sopenharmony_ci
10818c2ecf20Sopenharmony_ci	err = perf_evlist__parse_sample(session->evlist, event, &sample);
10828c2ecf20Sopenharmony_ci	if (err)
10838c2ecf20Sopenharmony_ci		return err;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	if (!sample.aux_sample.size)
10868c2ecf20Sopenharmony_ci		return 0;
10878c2ecf20Sopenharmony_ci
10888c2ecf20Sopenharmony_ci	offset += sample.aux_sample.data - (void *)event;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	return session->auxtrace->queue_data(session, &sample, NULL, offset);
10918c2ecf20Sopenharmony_ci}
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ciint auxtrace_queue_data(struct perf_session *session, bool samples, bool events)
10948c2ecf20Sopenharmony_ci{
10958c2ecf20Sopenharmony_ci	struct queue_data qd = {
10968c2ecf20Sopenharmony_ci		.samples = samples,
10978c2ecf20Sopenharmony_ci		.events = events,
10988c2ecf20Sopenharmony_ci	};
10998c2ecf20Sopenharmony_ci
11008c2ecf20Sopenharmony_ci	if (auxtrace__dont_decode(session))
11018c2ecf20Sopenharmony_ci		return 0;
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_ci	if (!session->auxtrace || !session->auxtrace->queue_data)
11048c2ecf20Sopenharmony_ci		return -EINVAL;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	return perf_session__peek_events(session, session->header.data_offset,
11078c2ecf20Sopenharmony_ci					 session->header.data_size,
11088c2ecf20Sopenharmony_ci					 auxtrace_queue_data_cb, &qd);
11098c2ecf20Sopenharmony_ci}
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_civoid *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	size_t adj = buffer->data_offset & (page_size - 1);
11148c2ecf20Sopenharmony_ci	size_t size = buffer->size + adj;
11158c2ecf20Sopenharmony_ci	off_t file_offset = buffer->data_offset - adj;
11168c2ecf20Sopenharmony_ci	void *addr;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	if (buffer->data)
11198c2ecf20Sopenharmony_ci		return buffer->data;
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset);
11228c2ecf20Sopenharmony_ci	if (addr == MAP_FAILED)
11238c2ecf20Sopenharmony_ci		return NULL;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	buffer->mmap_addr = addr;
11268c2ecf20Sopenharmony_ci	buffer->mmap_size = size;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	buffer->data = addr + adj;
11298c2ecf20Sopenharmony_ci
11308c2ecf20Sopenharmony_ci	return buffer->data;
11318c2ecf20Sopenharmony_ci}
11328c2ecf20Sopenharmony_ci
11338c2ecf20Sopenharmony_civoid auxtrace_buffer__put_data(struct auxtrace_buffer *buffer)
11348c2ecf20Sopenharmony_ci{
11358c2ecf20Sopenharmony_ci	if (!buffer->data || !buffer->mmap_addr)
11368c2ecf20Sopenharmony_ci		return;
11378c2ecf20Sopenharmony_ci	munmap(buffer->mmap_addr, buffer->mmap_size);
11388c2ecf20Sopenharmony_ci	buffer->mmap_addr = NULL;
11398c2ecf20Sopenharmony_ci	buffer->mmap_size = 0;
11408c2ecf20Sopenharmony_ci	buffer->data = NULL;
11418c2ecf20Sopenharmony_ci	buffer->use_data = NULL;
11428c2ecf20Sopenharmony_ci}
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_civoid auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer)
11458c2ecf20Sopenharmony_ci{
11468c2ecf20Sopenharmony_ci	auxtrace_buffer__put_data(buffer);
11478c2ecf20Sopenharmony_ci	if (buffer->data_needs_freeing) {
11488c2ecf20Sopenharmony_ci		buffer->data_needs_freeing = false;
11498c2ecf20Sopenharmony_ci		zfree(&buffer->data);
11508c2ecf20Sopenharmony_ci		buffer->use_data = NULL;
11518c2ecf20Sopenharmony_ci		buffer->size = 0;
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci}
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_civoid auxtrace_buffer__free(struct auxtrace_buffer *buffer)
11568c2ecf20Sopenharmony_ci{
11578c2ecf20Sopenharmony_ci	auxtrace_buffer__drop_data(buffer);
11588c2ecf20Sopenharmony_ci	free(buffer);
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci
11618c2ecf20Sopenharmony_civoid auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type,
11628c2ecf20Sopenharmony_ci			  int code, int cpu, pid_t pid, pid_t tid, u64 ip,
11638c2ecf20Sopenharmony_ci			  const char *msg, u64 timestamp)
11648c2ecf20Sopenharmony_ci{
11658c2ecf20Sopenharmony_ci	size_t size;
11668c2ecf20Sopenharmony_ci
11678c2ecf20Sopenharmony_ci	memset(auxtrace_error, 0, sizeof(struct perf_record_auxtrace_error));
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR;
11708c2ecf20Sopenharmony_ci	auxtrace_error->type = type;
11718c2ecf20Sopenharmony_ci	auxtrace_error->code = code;
11728c2ecf20Sopenharmony_ci	auxtrace_error->cpu = cpu;
11738c2ecf20Sopenharmony_ci	auxtrace_error->pid = pid;
11748c2ecf20Sopenharmony_ci	auxtrace_error->tid = tid;
11758c2ecf20Sopenharmony_ci	auxtrace_error->fmt = 1;
11768c2ecf20Sopenharmony_ci	auxtrace_error->ip = ip;
11778c2ecf20Sopenharmony_ci	auxtrace_error->time = timestamp;
11788c2ecf20Sopenharmony_ci	strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG);
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	size = (void *)auxtrace_error->msg - (void *)auxtrace_error +
11818c2ecf20Sopenharmony_ci	       strlen(auxtrace_error->msg) + 1;
11828c2ecf20Sopenharmony_ci	auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64));
11838c2ecf20Sopenharmony_ci}
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ciint perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr,
11868c2ecf20Sopenharmony_ci					 struct perf_tool *tool,
11878c2ecf20Sopenharmony_ci					 struct perf_session *session,
11888c2ecf20Sopenharmony_ci					 perf_event__handler_t process)
11898c2ecf20Sopenharmony_ci{
11908c2ecf20Sopenharmony_ci	union perf_event *ev;
11918c2ecf20Sopenharmony_ci	size_t priv_size;
11928c2ecf20Sopenharmony_ci	int err;
11938c2ecf20Sopenharmony_ci
11948c2ecf20Sopenharmony_ci	pr_debug2("Synthesizing auxtrace information\n");
11958c2ecf20Sopenharmony_ci	priv_size = auxtrace_record__info_priv_size(itr, session->evlist);
11968c2ecf20Sopenharmony_ci	ev = zalloc(sizeof(struct perf_record_auxtrace_info) + priv_size);
11978c2ecf20Sopenharmony_ci	if (!ev)
11988c2ecf20Sopenharmony_ci		return -ENOMEM;
11998c2ecf20Sopenharmony_ci
12008c2ecf20Sopenharmony_ci	ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO;
12018c2ecf20Sopenharmony_ci	ev->auxtrace_info.header.size = sizeof(struct perf_record_auxtrace_info) +
12028c2ecf20Sopenharmony_ci					priv_size;
12038c2ecf20Sopenharmony_ci	err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info,
12048c2ecf20Sopenharmony_ci					 priv_size);
12058c2ecf20Sopenharmony_ci	if (err)
12068c2ecf20Sopenharmony_ci		goto out_free;
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ci	err = process(tool, ev, NULL, NULL);
12098c2ecf20Sopenharmony_ciout_free:
12108c2ecf20Sopenharmony_ci	free(ev);
12118c2ecf20Sopenharmony_ci	return err;
12128c2ecf20Sopenharmony_ci}
12138c2ecf20Sopenharmony_ci
12148c2ecf20Sopenharmony_cistatic void unleader_evsel(struct evlist *evlist, struct evsel *leader)
12158c2ecf20Sopenharmony_ci{
12168c2ecf20Sopenharmony_ci	struct evsel *new_leader = NULL;
12178c2ecf20Sopenharmony_ci	struct evsel *evsel;
12188c2ecf20Sopenharmony_ci
12198c2ecf20Sopenharmony_ci	/* Find new leader for the group */
12208c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
12218c2ecf20Sopenharmony_ci		if (evsel->leader != leader || evsel == leader)
12228c2ecf20Sopenharmony_ci			continue;
12238c2ecf20Sopenharmony_ci		if (!new_leader)
12248c2ecf20Sopenharmony_ci			new_leader = evsel;
12258c2ecf20Sopenharmony_ci		evsel->leader = new_leader;
12268c2ecf20Sopenharmony_ci	}
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	/* Update group information */
12298c2ecf20Sopenharmony_ci	if (new_leader) {
12308c2ecf20Sopenharmony_ci		zfree(&new_leader->group_name);
12318c2ecf20Sopenharmony_ci		new_leader->group_name = leader->group_name;
12328c2ecf20Sopenharmony_ci		leader->group_name = NULL;
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci		new_leader->core.nr_members = leader->core.nr_members - 1;
12358c2ecf20Sopenharmony_ci		leader->core.nr_members = 1;
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci}
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_cistatic void unleader_auxtrace(struct perf_session *session)
12408c2ecf20Sopenharmony_ci{
12418c2ecf20Sopenharmony_ci	struct evsel *evsel;
12428c2ecf20Sopenharmony_ci
12438c2ecf20Sopenharmony_ci	evlist__for_each_entry(session->evlist, evsel) {
12448c2ecf20Sopenharmony_ci		if (auxtrace__evsel_is_auxtrace(session, evsel) &&
12458c2ecf20Sopenharmony_ci		    evsel__is_group_leader(evsel)) {
12468c2ecf20Sopenharmony_ci			unleader_evsel(session->evlist, evsel);
12478c2ecf20Sopenharmony_ci		}
12488c2ecf20Sopenharmony_ci	}
12498c2ecf20Sopenharmony_ci}
12508c2ecf20Sopenharmony_ci
12518c2ecf20Sopenharmony_ciint perf_event__process_auxtrace_info(struct perf_session *session,
12528c2ecf20Sopenharmony_ci				      union perf_event *event)
12538c2ecf20Sopenharmony_ci{
12548c2ecf20Sopenharmony_ci	enum auxtrace_type type = event->auxtrace_info.type;
12558c2ecf20Sopenharmony_ci	int err;
12568c2ecf20Sopenharmony_ci
12578c2ecf20Sopenharmony_ci	if (dump_trace)
12588c2ecf20Sopenharmony_ci		fprintf(stdout, " type: %u\n", type);
12598c2ecf20Sopenharmony_ci
12608c2ecf20Sopenharmony_ci	switch (type) {
12618c2ecf20Sopenharmony_ci	case PERF_AUXTRACE_INTEL_PT:
12628c2ecf20Sopenharmony_ci		err = intel_pt_process_auxtrace_info(event, session);
12638c2ecf20Sopenharmony_ci		break;
12648c2ecf20Sopenharmony_ci	case PERF_AUXTRACE_INTEL_BTS:
12658c2ecf20Sopenharmony_ci		err = intel_bts_process_auxtrace_info(event, session);
12668c2ecf20Sopenharmony_ci		break;
12678c2ecf20Sopenharmony_ci	case PERF_AUXTRACE_ARM_SPE:
12688c2ecf20Sopenharmony_ci		err = arm_spe_process_auxtrace_info(event, session);
12698c2ecf20Sopenharmony_ci		break;
12708c2ecf20Sopenharmony_ci	case PERF_AUXTRACE_CS_ETM:
12718c2ecf20Sopenharmony_ci		err = cs_etm__process_auxtrace_info(event, session);
12728c2ecf20Sopenharmony_ci		break;
12738c2ecf20Sopenharmony_ci	case PERF_AUXTRACE_S390_CPUMSF:
12748c2ecf20Sopenharmony_ci		err = s390_cpumsf_process_auxtrace_info(event, session);
12758c2ecf20Sopenharmony_ci		break;
12768c2ecf20Sopenharmony_ci	case PERF_AUXTRACE_UNKNOWN:
12778c2ecf20Sopenharmony_ci	default:
12788c2ecf20Sopenharmony_ci		return -EINVAL;
12798c2ecf20Sopenharmony_ci	}
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	if (err)
12828c2ecf20Sopenharmony_ci		return err;
12838c2ecf20Sopenharmony_ci
12848c2ecf20Sopenharmony_ci	unleader_auxtrace(session);
12858c2ecf20Sopenharmony_ci
12868c2ecf20Sopenharmony_ci	return 0;
12878c2ecf20Sopenharmony_ci}
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_cis64 perf_event__process_auxtrace(struct perf_session *session,
12908c2ecf20Sopenharmony_ci				 union perf_event *event)
12918c2ecf20Sopenharmony_ci{
12928c2ecf20Sopenharmony_ci	s64 err;
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci	if (dump_trace)
12958c2ecf20Sopenharmony_ci		fprintf(stdout, " size: %#"PRI_lx64"  offset: %#"PRI_lx64"  ref: %#"PRI_lx64"  idx: %u  tid: %d  cpu: %d\n",
12968c2ecf20Sopenharmony_ci			event->auxtrace.size, event->auxtrace.offset,
12978c2ecf20Sopenharmony_ci			event->auxtrace.reference, event->auxtrace.idx,
12988c2ecf20Sopenharmony_ci			event->auxtrace.tid, event->auxtrace.cpu);
12998c2ecf20Sopenharmony_ci
13008c2ecf20Sopenharmony_ci	if (auxtrace__dont_decode(session))
13018c2ecf20Sopenharmony_ci		return event->auxtrace.size;
13028c2ecf20Sopenharmony_ci
13038c2ecf20Sopenharmony_ci	if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE)
13048c2ecf20Sopenharmony_ci		return -EINVAL;
13058c2ecf20Sopenharmony_ci
13068c2ecf20Sopenharmony_ci	err = session->auxtrace->process_auxtrace_event(session, event, session->tool);
13078c2ecf20Sopenharmony_ci	if (err < 0)
13088c2ecf20Sopenharmony_ci		return err;
13098c2ecf20Sopenharmony_ci
13108c2ecf20Sopenharmony_ci	return event->auxtrace.size;
13118c2ecf20Sopenharmony_ci}
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci#define PERF_ITRACE_DEFAULT_PERIOD_TYPE		PERF_ITRACE_PERIOD_NANOSECS
13148c2ecf20Sopenharmony_ci#define PERF_ITRACE_DEFAULT_PERIOD		100000
13158c2ecf20Sopenharmony_ci#define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ	16
13168c2ecf20Sopenharmony_ci#define PERF_ITRACE_MAX_CALLCHAIN_SZ		1024
13178c2ecf20Sopenharmony_ci#define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ	64
13188c2ecf20Sopenharmony_ci#define PERF_ITRACE_MAX_LAST_BRANCH_SZ		1024
13198c2ecf20Sopenharmony_ci
13208c2ecf20Sopenharmony_civoid itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts,
13218c2ecf20Sopenharmony_ci				    bool no_sample)
13228c2ecf20Sopenharmony_ci{
13238c2ecf20Sopenharmony_ci	synth_opts->branches = true;
13248c2ecf20Sopenharmony_ci	synth_opts->transactions = true;
13258c2ecf20Sopenharmony_ci	synth_opts->ptwrites = true;
13268c2ecf20Sopenharmony_ci	synth_opts->pwr_events = true;
13278c2ecf20Sopenharmony_ci	synth_opts->other_events = true;
13288c2ecf20Sopenharmony_ci	synth_opts->errors = true;
13298c2ecf20Sopenharmony_ci	synth_opts->flc = true;
13308c2ecf20Sopenharmony_ci	synth_opts->llc = true;
13318c2ecf20Sopenharmony_ci	synth_opts->tlb = true;
13328c2ecf20Sopenharmony_ci	synth_opts->remote_access = true;
13338c2ecf20Sopenharmony_ci
13348c2ecf20Sopenharmony_ci	if (no_sample) {
13358c2ecf20Sopenharmony_ci		synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS;
13368c2ecf20Sopenharmony_ci		synth_opts->period = 1;
13378c2ecf20Sopenharmony_ci		synth_opts->calls = true;
13388c2ecf20Sopenharmony_ci	} else {
13398c2ecf20Sopenharmony_ci		synth_opts->instructions = true;
13408c2ecf20Sopenharmony_ci		synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE;
13418c2ecf20Sopenharmony_ci		synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
13428c2ecf20Sopenharmony_ci	}
13438c2ecf20Sopenharmony_ci	synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
13448c2ecf20Sopenharmony_ci	synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ;
13458c2ecf20Sopenharmony_ci	synth_opts->initial_skip = 0;
13468c2ecf20Sopenharmony_ci}
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_cistatic int get_flag(const char **ptr, unsigned int *flags)
13498c2ecf20Sopenharmony_ci{
13508c2ecf20Sopenharmony_ci	while (1) {
13518c2ecf20Sopenharmony_ci		char c = **ptr;
13528c2ecf20Sopenharmony_ci
13538c2ecf20Sopenharmony_ci		if (c >= 'a' && c <= 'z') {
13548c2ecf20Sopenharmony_ci			*flags |= 1 << (c - 'a');
13558c2ecf20Sopenharmony_ci			++*ptr;
13568c2ecf20Sopenharmony_ci			return 0;
13578c2ecf20Sopenharmony_ci		} else if (c == ' ') {
13588c2ecf20Sopenharmony_ci			++*ptr;
13598c2ecf20Sopenharmony_ci			continue;
13608c2ecf20Sopenharmony_ci		} else {
13618c2ecf20Sopenharmony_ci			return -1;
13628c2ecf20Sopenharmony_ci		}
13638c2ecf20Sopenharmony_ci	}
13648c2ecf20Sopenharmony_ci}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic int get_flags(const char **ptr, unsigned int *plus_flags, unsigned int *minus_flags)
13678c2ecf20Sopenharmony_ci{
13688c2ecf20Sopenharmony_ci	while (1) {
13698c2ecf20Sopenharmony_ci		switch (**ptr) {
13708c2ecf20Sopenharmony_ci		case '+':
13718c2ecf20Sopenharmony_ci			++*ptr;
13728c2ecf20Sopenharmony_ci			if (get_flag(ptr, plus_flags))
13738c2ecf20Sopenharmony_ci				return -1;
13748c2ecf20Sopenharmony_ci			break;
13758c2ecf20Sopenharmony_ci		case '-':
13768c2ecf20Sopenharmony_ci			++*ptr;
13778c2ecf20Sopenharmony_ci			if (get_flag(ptr, minus_flags))
13788c2ecf20Sopenharmony_ci				return -1;
13798c2ecf20Sopenharmony_ci			break;
13808c2ecf20Sopenharmony_ci		case ' ':
13818c2ecf20Sopenharmony_ci			++*ptr;
13828c2ecf20Sopenharmony_ci			break;
13838c2ecf20Sopenharmony_ci		default:
13848c2ecf20Sopenharmony_ci			return 0;
13858c2ecf20Sopenharmony_ci		}
13868c2ecf20Sopenharmony_ci	}
13878c2ecf20Sopenharmony_ci}
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci/*
13908c2ecf20Sopenharmony_ci * Please check tools/perf/Documentation/perf-script.txt for information
13918c2ecf20Sopenharmony_ci * about the options parsed here, which is introduced after this cset,
13928c2ecf20Sopenharmony_ci * when support in 'perf script' for these options is introduced.
13938c2ecf20Sopenharmony_ci */
13948c2ecf20Sopenharmony_ciint itrace_parse_synth_opts(const struct option *opt, const char *str,
13958c2ecf20Sopenharmony_ci			    int unset)
13968c2ecf20Sopenharmony_ci{
13978c2ecf20Sopenharmony_ci	struct itrace_synth_opts *synth_opts = opt->value;
13988c2ecf20Sopenharmony_ci	const char *p;
13998c2ecf20Sopenharmony_ci	char *endptr;
14008c2ecf20Sopenharmony_ci	bool period_type_set = false;
14018c2ecf20Sopenharmony_ci	bool period_set = false;
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	synth_opts->set = true;
14048c2ecf20Sopenharmony_ci
14058c2ecf20Sopenharmony_ci	if (unset) {
14068c2ecf20Sopenharmony_ci		synth_opts->dont_decode = true;
14078c2ecf20Sopenharmony_ci		return 0;
14088c2ecf20Sopenharmony_ci	}
14098c2ecf20Sopenharmony_ci
14108c2ecf20Sopenharmony_ci	if (!str) {
14118c2ecf20Sopenharmony_ci		itrace_synth_opts__set_default(synth_opts,
14128c2ecf20Sopenharmony_ci					       synth_opts->default_no_sample);
14138c2ecf20Sopenharmony_ci		return 0;
14148c2ecf20Sopenharmony_ci	}
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci	for (p = str; *p;) {
14178c2ecf20Sopenharmony_ci		switch (*p++) {
14188c2ecf20Sopenharmony_ci		case 'i':
14198c2ecf20Sopenharmony_ci			synth_opts->instructions = true;
14208c2ecf20Sopenharmony_ci			while (*p == ' ' || *p == ',')
14218c2ecf20Sopenharmony_ci				p += 1;
14228c2ecf20Sopenharmony_ci			if (isdigit(*p)) {
14238c2ecf20Sopenharmony_ci				synth_opts->period = strtoull(p, &endptr, 10);
14248c2ecf20Sopenharmony_ci				period_set = true;
14258c2ecf20Sopenharmony_ci				p = endptr;
14268c2ecf20Sopenharmony_ci				while (*p == ' ' || *p == ',')
14278c2ecf20Sopenharmony_ci					p += 1;
14288c2ecf20Sopenharmony_ci				switch (*p++) {
14298c2ecf20Sopenharmony_ci				case 'i':
14308c2ecf20Sopenharmony_ci					synth_opts->period_type =
14318c2ecf20Sopenharmony_ci						PERF_ITRACE_PERIOD_INSTRUCTIONS;
14328c2ecf20Sopenharmony_ci					period_type_set = true;
14338c2ecf20Sopenharmony_ci					break;
14348c2ecf20Sopenharmony_ci				case 't':
14358c2ecf20Sopenharmony_ci					synth_opts->period_type =
14368c2ecf20Sopenharmony_ci						PERF_ITRACE_PERIOD_TICKS;
14378c2ecf20Sopenharmony_ci					period_type_set = true;
14388c2ecf20Sopenharmony_ci					break;
14398c2ecf20Sopenharmony_ci				case 'm':
14408c2ecf20Sopenharmony_ci					synth_opts->period *= 1000;
14418c2ecf20Sopenharmony_ci					/* Fall through */
14428c2ecf20Sopenharmony_ci				case 'u':
14438c2ecf20Sopenharmony_ci					synth_opts->period *= 1000;
14448c2ecf20Sopenharmony_ci					/* Fall through */
14458c2ecf20Sopenharmony_ci				case 'n':
14468c2ecf20Sopenharmony_ci					if (*p++ != 's')
14478c2ecf20Sopenharmony_ci						goto out_err;
14488c2ecf20Sopenharmony_ci					synth_opts->period_type =
14498c2ecf20Sopenharmony_ci						PERF_ITRACE_PERIOD_NANOSECS;
14508c2ecf20Sopenharmony_ci					period_type_set = true;
14518c2ecf20Sopenharmony_ci					break;
14528c2ecf20Sopenharmony_ci				case '\0':
14538c2ecf20Sopenharmony_ci					goto out;
14548c2ecf20Sopenharmony_ci				default:
14558c2ecf20Sopenharmony_ci					goto out_err;
14568c2ecf20Sopenharmony_ci				}
14578c2ecf20Sopenharmony_ci			}
14588c2ecf20Sopenharmony_ci			break;
14598c2ecf20Sopenharmony_ci		case 'b':
14608c2ecf20Sopenharmony_ci			synth_opts->branches = true;
14618c2ecf20Sopenharmony_ci			break;
14628c2ecf20Sopenharmony_ci		case 'x':
14638c2ecf20Sopenharmony_ci			synth_opts->transactions = true;
14648c2ecf20Sopenharmony_ci			break;
14658c2ecf20Sopenharmony_ci		case 'w':
14668c2ecf20Sopenharmony_ci			synth_opts->ptwrites = true;
14678c2ecf20Sopenharmony_ci			break;
14688c2ecf20Sopenharmony_ci		case 'p':
14698c2ecf20Sopenharmony_ci			synth_opts->pwr_events = true;
14708c2ecf20Sopenharmony_ci			break;
14718c2ecf20Sopenharmony_ci		case 'o':
14728c2ecf20Sopenharmony_ci			synth_opts->other_events = true;
14738c2ecf20Sopenharmony_ci			break;
14748c2ecf20Sopenharmony_ci		case 'e':
14758c2ecf20Sopenharmony_ci			synth_opts->errors = true;
14768c2ecf20Sopenharmony_ci			if (get_flags(&p, &synth_opts->error_plus_flags,
14778c2ecf20Sopenharmony_ci				      &synth_opts->error_minus_flags))
14788c2ecf20Sopenharmony_ci				goto out_err;
14798c2ecf20Sopenharmony_ci			break;
14808c2ecf20Sopenharmony_ci		case 'd':
14818c2ecf20Sopenharmony_ci			synth_opts->log = true;
14828c2ecf20Sopenharmony_ci			if (get_flags(&p, &synth_opts->log_plus_flags,
14838c2ecf20Sopenharmony_ci				      &synth_opts->log_minus_flags))
14848c2ecf20Sopenharmony_ci				goto out_err;
14858c2ecf20Sopenharmony_ci			break;
14868c2ecf20Sopenharmony_ci		case 'c':
14878c2ecf20Sopenharmony_ci			synth_opts->branches = true;
14888c2ecf20Sopenharmony_ci			synth_opts->calls = true;
14898c2ecf20Sopenharmony_ci			break;
14908c2ecf20Sopenharmony_ci		case 'r':
14918c2ecf20Sopenharmony_ci			synth_opts->branches = true;
14928c2ecf20Sopenharmony_ci			synth_opts->returns = true;
14938c2ecf20Sopenharmony_ci			break;
14948c2ecf20Sopenharmony_ci		case 'G':
14958c2ecf20Sopenharmony_ci		case 'g':
14968c2ecf20Sopenharmony_ci			if (p[-1] == 'G')
14978c2ecf20Sopenharmony_ci				synth_opts->add_callchain = true;
14988c2ecf20Sopenharmony_ci			else
14998c2ecf20Sopenharmony_ci				synth_opts->callchain = true;
15008c2ecf20Sopenharmony_ci			synth_opts->callchain_sz =
15018c2ecf20Sopenharmony_ci					PERF_ITRACE_DEFAULT_CALLCHAIN_SZ;
15028c2ecf20Sopenharmony_ci			while (*p == ' ' || *p == ',')
15038c2ecf20Sopenharmony_ci				p += 1;
15048c2ecf20Sopenharmony_ci			if (isdigit(*p)) {
15058c2ecf20Sopenharmony_ci				unsigned int val;
15068c2ecf20Sopenharmony_ci
15078c2ecf20Sopenharmony_ci				val = strtoul(p, &endptr, 10);
15088c2ecf20Sopenharmony_ci				p = endptr;
15098c2ecf20Sopenharmony_ci				if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ)
15108c2ecf20Sopenharmony_ci					goto out_err;
15118c2ecf20Sopenharmony_ci				synth_opts->callchain_sz = val;
15128c2ecf20Sopenharmony_ci			}
15138c2ecf20Sopenharmony_ci			break;
15148c2ecf20Sopenharmony_ci		case 'L':
15158c2ecf20Sopenharmony_ci		case 'l':
15168c2ecf20Sopenharmony_ci			if (p[-1] == 'L')
15178c2ecf20Sopenharmony_ci				synth_opts->add_last_branch = true;
15188c2ecf20Sopenharmony_ci			else
15198c2ecf20Sopenharmony_ci				synth_opts->last_branch = true;
15208c2ecf20Sopenharmony_ci			synth_opts->last_branch_sz =
15218c2ecf20Sopenharmony_ci					PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ;
15228c2ecf20Sopenharmony_ci			while (*p == ' ' || *p == ',')
15238c2ecf20Sopenharmony_ci				p += 1;
15248c2ecf20Sopenharmony_ci			if (isdigit(*p)) {
15258c2ecf20Sopenharmony_ci				unsigned int val;
15268c2ecf20Sopenharmony_ci
15278c2ecf20Sopenharmony_ci				val = strtoul(p, &endptr, 10);
15288c2ecf20Sopenharmony_ci				p = endptr;
15298c2ecf20Sopenharmony_ci				if (!val ||
15308c2ecf20Sopenharmony_ci				    val > PERF_ITRACE_MAX_LAST_BRANCH_SZ)
15318c2ecf20Sopenharmony_ci					goto out_err;
15328c2ecf20Sopenharmony_ci				synth_opts->last_branch_sz = val;
15338c2ecf20Sopenharmony_ci			}
15348c2ecf20Sopenharmony_ci			break;
15358c2ecf20Sopenharmony_ci		case 's':
15368c2ecf20Sopenharmony_ci			synth_opts->initial_skip = strtoul(p, &endptr, 10);
15378c2ecf20Sopenharmony_ci			if (p == endptr)
15388c2ecf20Sopenharmony_ci				goto out_err;
15398c2ecf20Sopenharmony_ci			p = endptr;
15408c2ecf20Sopenharmony_ci			break;
15418c2ecf20Sopenharmony_ci		case 'f':
15428c2ecf20Sopenharmony_ci			synth_opts->flc = true;
15438c2ecf20Sopenharmony_ci			break;
15448c2ecf20Sopenharmony_ci		case 'm':
15458c2ecf20Sopenharmony_ci			synth_opts->llc = true;
15468c2ecf20Sopenharmony_ci			break;
15478c2ecf20Sopenharmony_ci		case 't':
15488c2ecf20Sopenharmony_ci			synth_opts->tlb = true;
15498c2ecf20Sopenharmony_ci			break;
15508c2ecf20Sopenharmony_ci		case 'a':
15518c2ecf20Sopenharmony_ci			synth_opts->remote_access = true;
15528c2ecf20Sopenharmony_ci			break;
15538c2ecf20Sopenharmony_ci		case 'q':
15548c2ecf20Sopenharmony_ci			synth_opts->quick += 1;
15558c2ecf20Sopenharmony_ci			break;
15568c2ecf20Sopenharmony_ci		case ' ':
15578c2ecf20Sopenharmony_ci		case ',':
15588c2ecf20Sopenharmony_ci			break;
15598c2ecf20Sopenharmony_ci		default:
15608c2ecf20Sopenharmony_ci			goto out_err;
15618c2ecf20Sopenharmony_ci		}
15628c2ecf20Sopenharmony_ci	}
15638c2ecf20Sopenharmony_ciout:
15648c2ecf20Sopenharmony_ci	if (synth_opts->instructions) {
15658c2ecf20Sopenharmony_ci		if (!period_type_set)
15668c2ecf20Sopenharmony_ci			synth_opts->period_type =
15678c2ecf20Sopenharmony_ci					PERF_ITRACE_DEFAULT_PERIOD_TYPE;
15688c2ecf20Sopenharmony_ci		if (!period_set)
15698c2ecf20Sopenharmony_ci			synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD;
15708c2ecf20Sopenharmony_ci	}
15718c2ecf20Sopenharmony_ci
15728c2ecf20Sopenharmony_ci	return 0;
15738c2ecf20Sopenharmony_ci
15748c2ecf20Sopenharmony_ciout_err:
15758c2ecf20Sopenharmony_ci	pr_err("Bad Instruction Tracing options '%s'\n", str);
15768c2ecf20Sopenharmony_ci	return -EINVAL;
15778c2ecf20Sopenharmony_ci}
15788c2ecf20Sopenharmony_ci
15798c2ecf20Sopenharmony_cistatic const char * const auxtrace_error_type_name[] = {
15808c2ecf20Sopenharmony_ci	[PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace",
15818c2ecf20Sopenharmony_ci};
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_cistatic const char *auxtrace_error_name(int type)
15848c2ecf20Sopenharmony_ci{
15858c2ecf20Sopenharmony_ci	const char *error_type_name = NULL;
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci	if (type < PERF_AUXTRACE_ERROR_MAX)
15888c2ecf20Sopenharmony_ci		error_type_name = auxtrace_error_type_name[type];
15898c2ecf20Sopenharmony_ci	if (!error_type_name)
15908c2ecf20Sopenharmony_ci		error_type_name = "unknown AUX";
15918c2ecf20Sopenharmony_ci	return error_type_name;
15928c2ecf20Sopenharmony_ci}
15938c2ecf20Sopenharmony_ci
15948c2ecf20Sopenharmony_cisize_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp)
15958c2ecf20Sopenharmony_ci{
15968c2ecf20Sopenharmony_ci	struct perf_record_auxtrace_error *e = &event->auxtrace_error;
15978c2ecf20Sopenharmony_ci	unsigned long long nsecs = e->time;
15988c2ecf20Sopenharmony_ci	const char *msg = e->msg;
15998c2ecf20Sopenharmony_ci	int ret;
16008c2ecf20Sopenharmony_ci
16018c2ecf20Sopenharmony_ci	ret = fprintf(fp, " %s error type %u",
16028c2ecf20Sopenharmony_ci		      auxtrace_error_name(e->type), e->type);
16038c2ecf20Sopenharmony_ci
16048c2ecf20Sopenharmony_ci	if (e->fmt && nsecs) {
16058c2ecf20Sopenharmony_ci		unsigned long secs = nsecs / NSEC_PER_SEC;
16068c2ecf20Sopenharmony_ci
16078c2ecf20Sopenharmony_ci		nsecs -= secs * NSEC_PER_SEC;
16088c2ecf20Sopenharmony_ci		ret += fprintf(fp, " time %lu.%09llu", secs, nsecs);
16098c2ecf20Sopenharmony_ci	} else {
16108c2ecf20Sopenharmony_ci		ret += fprintf(fp, " time 0");
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (!e->fmt)
16148c2ecf20Sopenharmony_ci		msg = (const char *)&e->time;
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %s\n",
16178c2ecf20Sopenharmony_ci		       e->cpu, e->pid, e->tid, e->ip, e->code, msg);
16188c2ecf20Sopenharmony_ci	return ret;
16198c2ecf20Sopenharmony_ci}
16208c2ecf20Sopenharmony_ci
16218c2ecf20Sopenharmony_civoid perf_session__auxtrace_error_inc(struct perf_session *session,
16228c2ecf20Sopenharmony_ci				      union perf_event *event)
16238c2ecf20Sopenharmony_ci{
16248c2ecf20Sopenharmony_ci	struct perf_record_auxtrace_error *e = &event->auxtrace_error;
16258c2ecf20Sopenharmony_ci
16268c2ecf20Sopenharmony_ci	if (e->type < PERF_AUXTRACE_ERROR_MAX)
16278c2ecf20Sopenharmony_ci		session->evlist->stats.nr_auxtrace_errors[e->type] += 1;
16288c2ecf20Sopenharmony_ci}
16298c2ecf20Sopenharmony_ci
16308c2ecf20Sopenharmony_civoid events_stats__auxtrace_error_warn(const struct events_stats *stats)
16318c2ecf20Sopenharmony_ci{
16328c2ecf20Sopenharmony_ci	int i;
16338c2ecf20Sopenharmony_ci
16348c2ecf20Sopenharmony_ci	for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) {
16358c2ecf20Sopenharmony_ci		if (!stats->nr_auxtrace_errors[i])
16368c2ecf20Sopenharmony_ci			continue;
16378c2ecf20Sopenharmony_ci		ui__warning("%u %s errors\n",
16388c2ecf20Sopenharmony_ci			    stats->nr_auxtrace_errors[i],
16398c2ecf20Sopenharmony_ci			    auxtrace_error_name(i));
16408c2ecf20Sopenharmony_ci	}
16418c2ecf20Sopenharmony_ci}
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ciint perf_event__process_auxtrace_error(struct perf_session *session,
16448c2ecf20Sopenharmony_ci				       union perf_event *event)
16458c2ecf20Sopenharmony_ci{
16468c2ecf20Sopenharmony_ci	if (auxtrace__dont_decode(session))
16478c2ecf20Sopenharmony_ci		return 0;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	perf_event__fprintf_auxtrace_error(event, stdout);
16508c2ecf20Sopenharmony_ci	return 0;
16518c2ecf20Sopenharmony_ci}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_cistatic int __auxtrace_mmap__read(struct mmap *map,
16548c2ecf20Sopenharmony_ci				 struct auxtrace_record *itr,
16558c2ecf20Sopenharmony_ci				 struct perf_tool *tool, process_auxtrace_t fn,
16568c2ecf20Sopenharmony_ci				 bool snapshot, size_t snapshot_size)
16578c2ecf20Sopenharmony_ci{
16588c2ecf20Sopenharmony_ci	struct auxtrace_mmap *mm = &map->auxtrace_mmap;
16598c2ecf20Sopenharmony_ci	u64 head, old = mm->prev, offset, ref;
16608c2ecf20Sopenharmony_ci	unsigned char *data = mm->base;
16618c2ecf20Sopenharmony_ci	size_t size, head_off, old_off, len1, len2, padding;
16628c2ecf20Sopenharmony_ci	union perf_event ev;
16638c2ecf20Sopenharmony_ci	void *data1, *data2;
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci	if (snapshot) {
16668c2ecf20Sopenharmony_ci		head = auxtrace_mmap__read_snapshot_head(mm);
16678c2ecf20Sopenharmony_ci		if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data,
16688c2ecf20Sopenharmony_ci						   &head, &old))
16698c2ecf20Sopenharmony_ci			return -1;
16708c2ecf20Sopenharmony_ci	} else {
16718c2ecf20Sopenharmony_ci		head = auxtrace_mmap__read_head(mm);
16728c2ecf20Sopenharmony_ci	}
16738c2ecf20Sopenharmony_ci
16748c2ecf20Sopenharmony_ci	if (old == head)
16758c2ecf20Sopenharmony_ci		return 0;
16768c2ecf20Sopenharmony_ci
16778c2ecf20Sopenharmony_ci	pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n",
16788c2ecf20Sopenharmony_ci		  mm->idx, old, head, head - old);
16798c2ecf20Sopenharmony_ci
16808c2ecf20Sopenharmony_ci	if (mm->mask) {
16818c2ecf20Sopenharmony_ci		head_off = head & mm->mask;
16828c2ecf20Sopenharmony_ci		old_off = old & mm->mask;
16838c2ecf20Sopenharmony_ci	} else {
16848c2ecf20Sopenharmony_ci		head_off = head % mm->len;
16858c2ecf20Sopenharmony_ci		old_off = old % mm->len;
16868c2ecf20Sopenharmony_ci	}
16878c2ecf20Sopenharmony_ci
16888c2ecf20Sopenharmony_ci	if (head_off > old_off)
16898c2ecf20Sopenharmony_ci		size = head_off - old_off;
16908c2ecf20Sopenharmony_ci	else
16918c2ecf20Sopenharmony_ci		size = mm->len - (old_off - head_off);
16928c2ecf20Sopenharmony_ci
16938c2ecf20Sopenharmony_ci	if (snapshot && size > snapshot_size)
16948c2ecf20Sopenharmony_ci		size = snapshot_size;
16958c2ecf20Sopenharmony_ci
16968c2ecf20Sopenharmony_ci	ref = auxtrace_record__reference(itr);
16978c2ecf20Sopenharmony_ci
16988c2ecf20Sopenharmony_ci	if (head > old || size <= head || mm->mask) {
16998c2ecf20Sopenharmony_ci		offset = head - size;
17008c2ecf20Sopenharmony_ci	} else {
17018c2ecf20Sopenharmony_ci		/*
17028c2ecf20Sopenharmony_ci		 * When the buffer size is not a power of 2, 'head' wraps at the
17038c2ecf20Sopenharmony_ci		 * highest multiple of the buffer size, so we have to subtract
17048c2ecf20Sopenharmony_ci		 * the remainder here.
17058c2ecf20Sopenharmony_ci		 */
17068c2ecf20Sopenharmony_ci		u64 rem = (0ULL - mm->len) % mm->len;
17078c2ecf20Sopenharmony_ci
17088c2ecf20Sopenharmony_ci		offset = head - size - rem;
17098c2ecf20Sopenharmony_ci	}
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci	if (size > head_off) {
17128c2ecf20Sopenharmony_ci		len1 = size - head_off;
17138c2ecf20Sopenharmony_ci		data1 = &data[mm->len - len1];
17148c2ecf20Sopenharmony_ci		len2 = head_off;
17158c2ecf20Sopenharmony_ci		data2 = &data[0];
17168c2ecf20Sopenharmony_ci	} else {
17178c2ecf20Sopenharmony_ci		len1 = size;
17188c2ecf20Sopenharmony_ci		data1 = &data[head_off - len1];
17198c2ecf20Sopenharmony_ci		len2 = 0;
17208c2ecf20Sopenharmony_ci		data2 = NULL;
17218c2ecf20Sopenharmony_ci	}
17228c2ecf20Sopenharmony_ci
17238c2ecf20Sopenharmony_ci	if (itr->alignment) {
17248c2ecf20Sopenharmony_ci		unsigned int unwanted = len1 % itr->alignment;
17258c2ecf20Sopenharmony_ci
17268c2ecf20Sopenharmony_ci		len1 -= unwanted;
17278c2ecf20Sopenharmony_ci		size -= unwanted;
17288c2ecf20Sopenharmony_ci	}
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	/* padding must be written by fn() e.g. record__process_auxtrace() */
17318c2ecf20Sopenharmony_ci	padding = size & (PERF_AUXTRACE_RECORD_ALIGNMENT - 1);
17328c2ecf20Sopenharmony_ci	if (padding)
17338c2ecf20Sopenharmony_ci		padding = PERF_AUXTRACE_RECORD_ALIGNMENT - padding;
17348c2ecf20Sopenharmony_ci
17358c2ecf20Sopenharmony_ci	memset(&ev, 0, sizeof(ev));
17368c2ecf20Sopenharmony_ci	ev.auxtrace.header.type = PERF_RECORD_AUXTRACE;
17378c2ecf20Sopenharmony_ci	ev.auxtrace.header.size = sizeof(ev.auxtrace);
17388c2ecf20Sopenharmony_ci	ev.auxtrace.size = size + padding;
17398c2ecf20Sopenharmony_ci	ev.auxtrace.offset = offset;
17408c2ecf20Sopenharmony_ci	ev.auxtrace.reference = ref;
17418c2ecf20Sopenharmony_ci	ev.auxtrace.idx = mm->idx;
17428c2ecf20Sopenharmony_ci	ev.auxtrace.tid = mm->tid;
17438c2ecf20Sopenharmony_ci	ev.auxtrace.cpu = mm->cpu;
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_ci	if (fn(tool, map, &ev, data1, len1, data2, len2))
17468c2ecf20Sopenharmony_ci		return -1;
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci	mm->prev = head;
17498c2ecf20Sopenharmony_ci
17508c2ecf20Sopenharmony_ci	if (!snapshot) {
17518c2ecf20Sopenharmony_ci		auxtrace_mmap__write_tail(mm, head);
17528c2ecf20Sopenharmony_ci		if (itr->read_finish) {
17538c2ecf20Sopenharmony_ci			int err;
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci			err = itr->read_finish(itr, mm->idx);
17568c2ecf20Sopenharmony_ci			if (err < 0)
17578c2ecf20Sopenharmony_ci				return err;
17588c2ecf20Sopenharmony_ci		}
17598c2ecf20Sopenharmony_ci	}
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	return 1;
17628c2ecf20Sopenharmony_ci}
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ciint auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr,
17658c2ecf20Sopenharmony_ci			struct perf_tool *tool, process_auxtrace_t fn)
17668c2ecf20Sopenharmony_ci{
17678c2ecf20Sopenharmony_ci	return __auxtrace_mmap__read(map, itr, tool, fn, false, 0);
17688c2ecf20Sopenharmony_ci}
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ciint auxtrace_mmap__read_snapshot(struct mmap *map,
17718c2ecf20Sopenharmony_ci				 struct auxtrace_record *itr,
17728c2ecf20Sopenharmony_ci				 struct perf_tool *tool, process_auxtrace_t fn,
17738c2ecf20Sopenharmony_ci				 size_t snapshot_size)
17748c2ecf20Sopenharmony_ci{
17758c2ecf20Sopenharmony_ci	return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size);
17768c2ecf20Sopenharmony_ci}
17778c2ecf20Sopenharmony_ci
17788c2ecf20Sopenharmony_ci/**
17798c2ecf20Sopenharmony_ci * struct auxtrace_cache - hash table to implement a cache
17808c2ecf20Sopenharmony_ci * @hashtable: the hashtable
17818c2ecf20Sopenharmony_ci * @sz: hashtable size (number of hlists)
17828c2ecf20Sopenharmony_ci * @entry_size: size of an entry
17838c2ecf20Sopenharmony_ci * @limit: limit the number of entries to this maximum, when reached the cache
17848c2ecf20Sopenharmony_ci *         is dropped and caching begins again with an empty cache
17858c2ecf20Sopenharmony_ci * @cnt: current number of entries
17868c2ecf20Sopenharmony_ci * @bits: hashtable size (@sz = 2^@bits)
17878c2ecf20Sopenharmony_ci */
17888c2ecf20Sopenharmony_cistruct auxtrace_cache {
17898c2ecf20Sopenharmony_ci	struct hlist_head *hashtable;
17908c2ecf20Sopenharmony_ci	size_t sz;
17918c2ecf20Sopenharmony_ci	size_t entry_size;
17928c2ecf20Sopenharmony_ci	size_t limit;
17938c2ecf20Sopenharmony_ci	size_t cnt;
17948c2ecf20Sopenharmony_ci	unsigned int bits;
17958c2ecf20Sopenharmony_ci};
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_cistruct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size,
17988c2ecf20Sopenharmony_ci					   unsigned int limit_percent)
17998c2ecf20Sopenharmony_ci{
18008c2ecf20Sopenharmony_ci	struct auxtrace_cache *c;
18018c2ecf20Sopenharmony_ci	struct hlist_head *ht;
18028c2ecf20Sopenharmony_ci	size_t sz, i;
18038c2ecf20Sopenharmony_ci
18048c2ecf20Sopenharmony_ci	c = zalloc(sizeof(struct auxtrace_cache));
18058c2ecf20Sopenharmony_ci	if (!c)
18068c2ecf20Sopenharmony_ci		return NULL;
18078c2ecf20Sopenharmony_ci
18088c2ecf20Sopenharmony_ci	sz = 1UL << bits;
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	ht = calloc(sz, sizeof(struct hlist_head));
18118c2ecf20Sopenharmony_ci	if (!ht)
18128c2ecf20Sopenharmony_ci		goto out_free;
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	for (i = 0; i < sz; i++)
18158c2ecf20Sopenharmony_ci		INIT_HLIST_HEAD(&ht[i]);
18168c2ecf20Sopenharmony_ci
18178c2ecf20Sopenharmony_ci	c->hashtable = ht;
18188c2ecf20Sopenharmony_ci	c->sz = sz;
18198c2ecf20Sopenharmony_ci	c->entry_size = entry_size;
18208c2ecf20Sopenharmony_ci	c->limit = (c->sz * limit_percent) / 100;
18218c2ecf20Sopenharmony_ci	c->bits = bits;
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	return c;
18248c2ecf20Sopenharmony_ci
18258c2ecf20Sopenharmony_ciout_free:
18268c2ecf20Sopenharmony_ci	free(c);
18278c2ecf20Sopenharmony_ci	return NULL;
18288c2ecf20Sopenharmony_ci}
18298c2ecf20Sopenharmony_ci
18308c2ecf20Sopenharmony_cistatic void auxtrace_cache__drop(struct auxtrace_cache *c)
18318c2ecf20Sopenharmony_ci{
18328c2ecf20Sopenharmony_ci	struct auxtrace_cache_entry *entry;
18338c2ecf20Sopenharmony_ci	struct hlist_node *tmp;
18348c2ecf20Sopenharmony_ci	size_t i;
18358c2ecf20Sopenharmony_ci
18368c2ecf20Sopenharmony_ci	if (!c)
18378c2ecf20Sopenharmony_ci		return;
18388c2ecf20Sopenharmony_ci
18398c2ecf20Sopenharmony_ci	for (i = 0; i < c->sz; i++) {
18408c2ecf20Sopenharmony_ci		hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) {
18418c2ecf20Sopenharmony_ci			hlist_del(&entry->hash);
18428c2ecf20Sopenharmony_ci			auxtrace_cache__free_entry(c, entry);
18438c2ecf20Sopenharmony_ci		}
18448c2ecf20Sopenharmony_ci	}
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	c->cnt = 0;
18478c2ecf20Sopenharmony_ci}
18488c2ecf20Sopenharmony_ci
18498c2ecf20Sopenharmony_civoid auxtrace_cache__free(struct auxtrace_cache *c)
18508c2ecf20Sopenharmony_ci{
18518c2ecf20Sopenharmony_ci	if (!c)
18528c2ecf20Sopenharmony_ci		return;
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci	auxtrace_cache__drop(c);
18558c2ecf20Sopenharmony_ci	zfree(&c->hashtable);
18568c2ecf20Sopenharmony_ci	free(c);
18578c2ecf20Sopenharmony_ci}
18588c2ecf20Sopenharmony_ci
18598c2ecf20Sopenharmony_civoid *auxtrace_cache__alloc_entry(struct auxtrace_cache *c)
18608c2ecf20Sopenharmony_ci{
18618c2ecf20Sopenharmony_ci	return malloc(c->entry_size);
18628c2ecf20Sopenharmony_ci}
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_civoid auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused,
18658c2ecf20Sopenharmony_ci				void *entry)
18668c2ecf20Sopenharmony_ci{
18678c2ecf20Sopenharmony_ci	free(entry);
18688c2ecf20Sopenharmony_ci}
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ciint auxtrace_cache__add(struct auxtrace_cache *c, u32 key,
18718c2ecf20Sopenharmony_ci			struct auxtrace_cache_entry *entry)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	if (c->limit && ++c->cnt > c->limit)
18748c2ecf20Sopenharmony_ci		auxtrace_cache__drop(c);
18758c2ecf20Sopenharmony_ci
18768c2ecf20Sopenharmony_ci	entry->key = key;
18778c2ecf20Sopenharmony_ci	hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	return 0;
18808c2ecf20Sopenharmony_ci}
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_cistatic struct auxtrace_cache_entry *auxtrace_cache__rm(struct auxtrace_cache *c,
18838c2ecf20Sopenharmony_ci						       u32 key)
18848c2ecf20Sopenharmony_ci{
18858c2ecf20Sopenharmony_ci	struct auxtrace_cache_entry *entry;
18868c2ecf20Sopenharmony_ci	struct hlist_head *hlist;
18878c2ecf20Sopenharmony_ci	struct hlist_node *n;
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci	if (!c)
18908c2ecf20Sopenharmony_ci		return NULL;
18918c2ecf20Sopenharmony_ci
18928c2ecf20Sopenharmony_ci	hlist = &c->hashtable[hash_32(key, c->bits)];
18938c2ecf20Sopenharmony_ci	hlist_for_each_entry_safe(entry, n, hlist, hash) {
18948c2ecf20Sopenharmony_ci		if (entry->key == key) {
18958c2ecf20Sopenharmony_ci			hlist_del(&entry->hash);
18968c2ecf20Sopenharmony_ci			return entry;
18978c2ecf20Sopenharmony_ci		}
18988c2ecf20Sopenharmony_ci	}
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	return NULL;
19018c2ecf20Sopenharmony_ci}
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_civoid auxtrace_cache__remove(struct auxtrace_cache *c, u32 key)
19048c2ecf20Sopenharmony_ci{
19058c2ecf20Sopenharmony_ci	struct auxtrace_cache_entry *entry = auxtrace_cache__rm(c, key);
19068c2ecf20Sopenharmony_ci
19078c2ecf20Sopenharmony_ci	auxtrace_cache__free_entry(c, entry);
19088c2ecf20Sopenharmony_ci}
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_civoid *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key)
19118c2ecf20Sopenharmony_ci{
19128c2ecf20Sopenharmony_ci	struct auxtrace_cache_entry *entry;
19138c2ecf20Sopenharmony_ci	struct hlist_head *hlist;
19148c2ecf20Sopenharmony_ci
19158c2ecf20Sopenharmony_ci	if (!c)
19168c2ecf20Sopenharmony_ci		return NULL;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	hlist = &c->hashtable[hash_32(key, c->bits)];
19198c2ecf20Sopenharmony_ci	hlist_for_each_entry(entry, hlist, hash) {
19208c2ecf20Sopenharmony_ci		if (entry->key == key)
19218c2ecf20Sopenharmony_ci			return entry;
19228c2ecf20Sopenharmony_ci	}
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	return NULL;
19258c2ecf20Sopenharmony_ci}
19268c2ecf20Sopenharmony_ci
19278c2ecf20Sopenharmony_cistatic void addr_filter__free_str(struct addr_filter *filt)
19288c2ecf20Sopenharmony_ci{
19298c2ecf20Sopenharmony_ci	zfree(&filt->str);
19308c2ecf20Sopenharmony_ci	filt->action   = NULL;
19318c2ecf20Sopenharmony_ci	filt->sym_from = NULL;
19328c2ecf20Sopenharmony_ci	filt->sym_to   = NULL;
19338c2ecf20Sopenharmony_ci	filt->filename = NULL;
19348c2ecf20Sopenharmony_ci}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_cistatic struct addr_filter *addr_filter__new(void)
19378c2ecf20Sopenharmony_ci{
19388c2ecf20Sopenharmony_ci	struct addr_filter *filt = zalloc(sizeof(*filt));
19398c2ecf20Sopenharmony_ci
19408c2ecf20Sopenharmony_ci	if (filt)
19418c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&filt->list);
19428c2ecf20Sopenharmony_ci
19438c2ecf20Sopenharmony_ci	return filt;
19448c2ecf20Sopenharmony_ci}
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_cistatic void addr_filter__free(struct addr_filter *filt)
19478c2ecf20Sopenharmony_ci{
19488c2ecf20Sopenharmony_ci	if (filt)
19498c2ecf20Sopenharmony_ci		addr_filter__free_str(filt);
19508c2ecf20Sopenharmony_ci	free(filt);
19518c2ecf20Sopenharmony_ci}
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_cistatic void addr_filters__add(struct addr_filters *filts,
19548c2ecf20Sopenharmony_ci			      struct addr_filter *filt)
19558c2ecf20Sopenharmony_ci{
19568c2ecf20Sopenharmony_ci	list_add_tail(&filt->list, &filts->head);
19578c2ecf20Sopenharmony_ci	filts->cnt += 1;
19588c2ecf20Sopenharmony_ci}
19598c2ecf20Sopenharmony_ci
19608c2ecf20Sopenharmony_cistatic void addr_filters__del(struct addr_filters *filts,
19618c2ecf20Sopenharmony_ci			      struct addr_filter *filt)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	list_del_init(&filt->list);
19648c2ecf20Sopenharmony_ci	filts->cnt -= 1;
19658c2ecf20Sopenharmony_ci}
19668c2ecf20Sopenharmony_ci
19678c2ecf20Sopenharmony_civoid addr_filters__init(struct addr_filters *filts)
19688c2ecf20Sopenharmony_ci{
19698c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&filts->head);
19708c2ecf20Sopenharmony_ci	filts->cnt = 0;
19718c2ecf20Sopenharmony_ci}
19728c2ecf20Sopenharmony_ci
19738c2ecf20Sopenharmony_civoid addr_filters__exit(struct addr_filters *filts)
19748c2ecf20Sopenharmony_ci{
19758c2ecf20Sopenharmony_ci	struct addr_filter *filt, *n;
19768c2ecf20Sopenharmony_ci
19778c2ecf20Sopenharmony_ci	list_for_each_entry_safe(filt, n, &filts->head, list) {
19788c2ecf20Sopenharmony_ci		addr_filters__del(filts, filt);
19798c2ecf20Sopenharmony_ci		addr_filter__free(filt);
19808c2ecf20Sopenharmony_ci	}
19818c2ecf20Sopenharmony_ci}
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_cistatic int parse_num_or_str(char **inp, u64 *num, const char **str,
19848c2ecf20Sopenharmony_ci			    const char *str_delim)
19858c2ecf20Sopenharmony_ci{
19868c2ecf20Sopenharmony_ci	*inp += strspn(*inp, " ");
19878c2ecf20Sopenharmony_ci
19888c2ecf20Sopenharmony_ci	if (isdigit(**inp)) {
19898c2ecf20Sopenharmony_ci		char *endptr;
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_ci		if (!num)
19928c2ecf20Sopenharmony_ci			return -EINVAL;
19938c2ecf20Sopenharmony_ci		errno = 0;
19948c2ecf20Sopenharmony_ci		*num = strtoull(*inp, &endptr, 0);
19958c2ecf20Sopenharmony_ci		if (errno)
19968c2ecf20Sopenharmony_ci			return -errno;
19978c2ecf20Sopenharmony_ci		if (endptr == *inp)
19988c2ecf20Sopenharmony_ci			return -EINVAL;
19998c2ecf20Sopenharmony_ci		*inp = endptr;
20008c2ecf20Sopenharmony_ci	} else {
20018c2ecf20Sopenharmony_ci		size_t n;
20028c2ecf20Sopenharmony_ci
20038c2ecf20Sopenharmony_ci		if (!str)
20048c2ecf20Sopenharmony_ci			return -EINVAL;
20058c2ecf20Sopenharmony_ci		*inp += strspn(*inp, " ");
20068c2ecf20Sopenharmony_ci		*str = *inp;
20078c2ecf20Sopenharmony_ci		n = strcspn(*inp, str_delim);
20088c2ecf20Sopenharmony_ci		if (!n)
20098c2ecf20Sopenharmony_ci			return -EINVAL;
20108c2ecf20Sopenharmony_ci		*inp += n;
20118c2ecf20Sopenharmony_ci		if (**inp) {
20128c2ecf20Sopenharmony_ci			**inp = '\0';
20138c2ecf20Sopenharmony_ci			*inp += 1;
20148c2ecf20Sopenharmony_ci		}
20158c2ecf20Sopenharmony_ci	}
20168c2ecf20Sopenharmony_ci	return 0;
20178c2ecf20Sopenharmony_ci}
20188c2ecf20Sopenharmony_ci
20198c2ecf20Sopenharmony_cistatic int parse_action(struct addr_filter *filt)
20208c2ecf20Sopenharmony_ci{
20218c2ecf20Sopenharmony_ci	if (!strcmp(filt->action, "filter")) {
20228c2ecf20Sopenharmony_ci		filt->start = true;
20238c2ecf20Sopenharmony_ci		filt->range = true;
20248c2ecf20Sopenharmony_ci	} else if (!strcmp(filt->action, "start")) {
20258c2ecf20Sopenharmony_ci		filt->start = true;
20268c2ecf20Sopenharmony_ci	} else if (!strcmp(filt->action, "stop")) {
20278c2ecf20Sopenharmony_ci		filt->start = false;
20288c2ecf20Sopenharmony_ci	} else if (!strcmp(filt->action, "tracestop")) {
20298c2ecf20Sopenharmony_ci		filt->start = false;
20308c2ecf20Sopenharmony_ci		filt->range = true;
20318c2ecf20Sopenharmony_ci		filt->action += 5; /* Change 'tracestop' to 'stop' */
20328c2ecf20Sopenharmony_ci	} else {
20338c2ecf20Sopenharmony_ci		return -EINVAL;
20348c2ecf20Sopenharmony_ci	}
20358c2ecf20Sopenharmony_ci	return 0;
20368c2ecf20Sopenharmony_ci}
20378c2ecf20Sopenharmony_ci
20388c2ecf20Sopenharmony_cistatic int parse_sym_idx(char **inp, int *idx)
20398c2ecf20Sopenharmony_ci{
20408c2ecf20Sopenharmony_ci	*idx = -1;
20418c2ecf20Sopenharmony_ci
20428c2ecf20Sopenharmony_ci	*inp += strspn(*inp, " ");
20438c2ecf20Sopenharmony_ci
20448c2ecf20Sopenharmony_ci	if (**inp != '#')
20458c2ecf20Sopenharmony_ci		return 0;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci	*inp += 1;
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	if (**inp == 'g' || **inp == 'G') {
20508c2ecf20Sopenharmony_ci		*inp += 1;
20518c2ecf20Sopenharmony_ci		*idx = 0;
20528c2ecf20Sopenharmony_ci	} else {
20538c2ecf20Sopenharmony_ci		unsigned long num;
20548c2ecf20Sopenharmony_ci		char *endptr;
20558c2ecf20Sopenharmony_ci
20568c2ecf20Sopenharmony_ci		errno = 0;
20578c2ecf20Sopenharmony_ci		num = strtoul(*inp, &endptr, 0);
20588c2ecf20Sopenharmony_ci		if (errno)
20598c2ecf20Sopenharmony_ci			return -errno;
20608c2ecf20Sopenharmony_ci		if (endptr == *inp || num > INT_MAX)
20618c2ecf20Sopenharmony_ci			return -EINVAL;
20628c2ecf20Sopenharmony_ci		*inp = endptr;
20638c2ecf20Sopenharmony_ci		*idx = num;
20648c2ecf20Sopenharmony_ci	}
20658c2ecf20Sopenharmony_ci
20668c2ecf20Sopenharmony_ci	return 0;
20678c2ecf20Sopenharmony_ci}
20688c2ecf20Sopenharmony_ci
20698c2ecf20Sopenharmony_cistatic int parse_addr_size(char **inp, u64 *num, const char **str, int *idx)
20708c2ecf20Sopenharmony_ci{
20718c2ecf20Sopenharmony_ci	int err = parse_num_or_str(inp, num, str, " ");
20728c2ecf20Sopenharmony_ci
20738c2ecf20Sopenharmony_ci	if (!err && *str)
20748c2ecf20Sopenharmony_ci		err = parse_sym_idx(inp, idx);
20758c2ecf20Sopenharmony_ci
20768c2ecf20Sopenharmony_ci	return err;
20778c2ecf20Sopenharmony_ci}
20788c2ecf20Sopenharmony_ci
20798c2ecf20Sopenharmony_cistatic int parse_one_filter(struct addr_filter *filt, const char **filter_inp)
20808c2ecf20Sopenharmony_ci{
20818c2ecf20Sopenharmony_ci	char *fstr;
20828c2ecf20Sopenharmony_ci	int err;
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	filt->str = fstr = strdup(*filter_inp);
20858c2ecf20Sopenharmony_ci	if (!fstr)
20868c2ecf20Sopenharmony_ci		return -ENOMEM;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	err = parse_num_or_str(&fstr, NULL, &filt->action, " ");
20898c2ecf20Sopenharmony_ci	if (err)
20908c2ecf20Sopenharmony_ci		goto out_err;
20918c2ecf20Sopenharmony_ci
20928c2ecf20Sopenharmony_ci	err = parse_action(filt);
20938c2ecf20Sopenharmony_ci	if (err)
20948c2ecf20Sopenharmony_ci		goto out_err;
20958c2ecf20Sopenharmony_ci
20968c2ecf20Sopenharmony_ci	err = parse_addr_size(&fstr, &filt->addr, &filt->sym_from,
20978c2ecf20Sopenharmony_ci			      &filt->sym_from_idx);
20988c2ecf20Sopenharmony_ci	if (err)
20998c2ecf20Sopenharmony_ci		goto out_err;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	fstr += strspn(fstr, " ");
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	if (*fstr == '/') {
21048c2ecf20Sopenharmony_ci		fstr += 1;
21058c2ecf20Sopenharmony_ci		err = parse_addr_size(&fstr, &filt->size, &filt->sym_to,
21068c2ecf20Sopenharmony_ci				      &filt->sym_to_idx);
21078c2ecf20Sopenharmony_ci		if (err)
21088c2ecf20Sopenharmony_ci			goto out_err;
21098c2ecf20Sopenharmony_ci		filt->range = true;
21108c2ecf20Sopenharmony_ci	}
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	fstr += strspn(fstr, " ");
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci	if (*fstr == '@') {
21158c2ecf20Sopenharmony_ci		fstr += 1;
21168c2ecf20Sopenharmony_ci		err = parse_num_or_str(&fstr, NULL, &filt->filename, " ,");
21178c2ecf20Sopenharmony_ci		if (err)
21188c2ecf20Sopenharmony_ci			goto out_err;
21198c2ecf20Sopenharmony_ci	}
21208c2ecf20Sopenharmony_ci
21218c2ecf20Sopenharmony_ci	fstr += strspn(fstr, " ,");
21228c2ecf20Sopenharmony_ci
21238c2ecf20Sopenharmony_ci	*filter_inp += fstr - filt->str;
21248c2ecf20Sopenharmony_ci
21258c2ecf20Sopenharmony_ci	return 0;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ciout_err:
21288c2ecf20Sopenharmony_ci	addr_filter__free_str(filt);
21298c2ecf20Sopenharmony_ci
21308c2ecf20Sopenharmony_ci	return err;
21318c2ecf20Sopenharmony_ci}
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ciint addr_filters__parse_bare_filter(struct addr_filters *filts,
21348c2ecf20Sopenharmony_ci				    const char *filter)
21358c2ecf20Sopenharmony_ci{
21368c2ecf20Sopenharmony_ci	struct addr_filter *filt;
21378c2ecf20Sopenharmony_ci	const char *fstr = filter;
21388c2ecf20Sopenharmony_ci	int err;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	while (*fstr) {
21418c2ecf20Sopenharmony_ci		filt = addr_filter__new();
21428c2ecf20Sopenharmony_ci		err = parse_one_filter(filt, &fstr);
21438c2ecf20Sopenharmony_ci		if (err) {
21448c2ecf20Sopenharmony_ci			addr_filter__free(filt);
21458c2ecf20Sopenharmony_ci			addr_filters__exit(filts);
21468c2ecf20Sopenharmony_ci			return err;
21478c2ecf20Sopenharmony_ci		}
21488c2ecf20Sopenharmony_ci		addr_filters__add(filts, filt);
21498c2ecf20Sopenharmony_ci	}
21508c2ecf20Sopenharmony_ci
21518c2ecf20Sopenharmony_ci	return 0;
21528c2ecf20Sopenharmony_ci}
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_cistruct sym_args {
21558c2ecf20Sopenharmony_ci	const char	*name;
21568c2ecf20Sopenharmony_ci	u64		start;
21578c2ecf20Sopenharmony_ci	u64		size;
21588c2ecf20Sopenharmony_ci	int		idx;
21598c2ecf20Sopenharmony_ci	int		cnt;
21608c2ecf20Sopenharmony_ci	bool		started;
21618c2ecf20Sopenharmony_ci	bool		global;
21628c2ecf20Sopenharmony_ci	bool		selected;
21638c2ecf20Sopenharmony_ci	bool		duplicate;
21648c2ecf20Sopenharmony_ci	bool		near;
21658c2ecf20Sopenharmony_ci};
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_cistatic bool kern_sym_name_match(const char *kname, const char *name)
21688c2ecf20Sopenharmony_ci{
21698c2ecf20Sopenharmony_ci	size_t n = strlen(name);
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci	return !strcmp(kname, name) ||
21728c2ecf20Sopenharmony_ci	       (!strncmp(kname, name, n) && kname[n] == '\t');
21738c2ecf20Sopenharmony_ci}
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_cistatic bool kern_sym_match(struct sym_args *args, const char *name, char type)
21768c2ecf20Sopenharmony_ci{
21778c2ecf20Sopenharmony_ci	/* A function with the same name, and global or the n'th found or any */
21788c2ecf20Sopenharmony_ci	return kallsyms__is_function(type) &&
21798c2ecf20Sopenharmony_ci	       kern_sym_name_match(name, args->name) &&
21808c2ecf20Sopenharmony_ci	       ((args->global && isupper(type)) ||
21818c2ecf20Sopenharmony_ci		(args->selected && ++(args->cnt) == args->idx) ||
21828c2ecf20Sopenharmony_ci		(!args->global && !args->selected));
21838c2ecf20Sopenharmony_ci}
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_cistatic int find_kern_sym_cb(void *arg, const char *name, char type, u64 start)
21868c2ecf20Sopenharmony_ci{
21878c2ecf20Sopenharmony_ci	struct sym_args *args = arg;
21888c2ecf20Sopenharmony_ci
21898c2ecf20Sopenharmony_ci	if (args->started) {
21908c2ecf20Sopenharmony_ci		if (!args->size)
21918c2ecf20Sopenharmony_ci			args->size = start - args->start;
21928c2ecf20Sopenharmony_ci		if (args->selected) {
21938c2ecf20Sopenharmony_ci			if (args->size)
21948c2ecf20Sopenharmony_ci				return 1;
21958c2ecf20Sopenharmony_ci		} else if (kern_sym_match(args, name, type)) {
21968c2ecf20Sopenharmony_ci			args->duplicate = true;
21978c2ecf20Sopenharmony_ci			return 1;
21988c2ecf20Sopenharmony_ci		}
21998c2ecf20Sopenharmony_ci	} else if (kern_sym_match(args, name, type)) {
22008c2ecf20Sopenharmony_ci		args->started = true;
22018c2ecf20Sopenharmony_ci		args->start = start;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	return 0;
22058c2ecf20Sopenharmony_ci}
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_cistatic int print_kern_sym_cb(void *arg, const char *name, char type, u64 start)
22088c2ecf20Sopenharmony_ci{
22098c2ecf20Sopenharmony_ci	struct sym_args *args = arg;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci	if (kern_sym_match(args, name, type)) {
22128c2ecf20Sopenharmony_ci		pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
22138c2ecf20Sopenharmony_ci		       ++args->cnt, start, type, name);
22148c2ecf20Sopenharmony_ci		args->near = true;
22158c2ecf20Sopenharmony_ci	} else if (args->near) {
22168c2ecf20Sopenharmony_ci		args->near = false;
22178c2ecf20Sopenharmony_ci		pr_err("\t\twhich is near\t\t%s\n", name);
22188c2ecf20Sopenharmony_ci	}
22198c2ecf20Sopenharmony_ci
22208c2ecf20Sopenharmony_ci	return 0;
22218c2ecf20Sopenharmony_ci}
22228c2ecf20Sopenharmony_ci
22238c2ecf20Sopenharmony_cistatic int sym_not_found_error(const char *sym_name, int idx)
22248c2ecf20Sopenharmony_ci{
22258c2ecf20Sopenharmony_ci	if (idx > 0) {
22268c2ecf20Sopenharmony_ci		pr_err("N'th occurrence (N=%d) of symbol '%s' not found.\n",
22278c2ecf20Sopenharmony_ci		       idx, sym_name);
22288c2ecf20Sopenharmony_ci	} else if (!idx) {
22298c2ecf20Sopenharmony_ci		pr_err("Global symbol '%s' not found.\n", sym_name);
22308c2ecf20Sopenharmony_ci	} else {
22318c2ecf20Sopenharmony_ci		pr_err("Symbol '%s' not found.\n", sym_name);
22328c2ecf20Sopenharmony_ci	}
22338c2ecf20Sopenharmony_ci	pr_err("Note that symbols must be functions.\n");
22348c2ecf20Sopenharmony_ci
22358c2ecf20Sopenharmony_ci	return -EINVAL;
22368c2ecf20Sopenharmony_ci}
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_cistatic int find_kern_sym(const char *sym_name, u64 *start, u64 *size, int idx)
22398c2ecf20Sopenharmony_ci{
22408c2ecf20Sopenharmony_ci	struct sym_args args = {
22418c2ecf20Sopenharmony_ci		.name = sym_name,
22428c2ecf20Sopenharmony_ci		.idx = idx,
22438c2ecf20Sopenharmony_ci		.global = !idx,
22448c2ecf20Sopenharmony_ci		.selected = idx > 0,
22458c2ecf20Sopenharmony_ci	};
22468c2ecf20Sopenharmony_ci	int err;
22478c2ecf20Sopenharmony_ci
22488c2ecf20Sopenharmony_ci	*start = 0;
22498c2ecf20Sopenharmony_ci	*size = 0;
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci	err = kallsyms__parse("/proc/kallsyms", &args, find_kern_sym_cb);
22528c2ecf20Sopenharmony_ci	if (err < 0) {
22538c2ecf20Sopenharmony_ci		pr_err("Failed to parse /proc/kallsyms\n");
22548c2ecf20Sopenharmony_ci		return err;
22558c2ecf20Sopenharmony_ci	}
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	if (args.duplicate) {
22588c2ecf20Sopenharmony_ci		pr_err("Multiple kernel symbols with name '%s'\n", sym_name);
22598c2ecf20Sopenharmony_ci		args.cnt = 0;
22608c2ecf20Sopenharmony_ci		kallsyms__parse("/proc/kallsyms", &args, print_kern_sym_cb);
22618c2ecf20Sopenharmony_ci		pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n",
22628c2ecf20Sopenharmony_ci		       sym_name);
22638c2ecf20Sopenharmony_ci		pr_err("Or select a global symbol by inserting #0 or #g or #G\n");
22648c2ecf20Sopenharmony_ci		return -EINVAL;
22658c2ecf20Sopenharmony_ci	}
22668c2ecf20Sopenharmony_ci
22678c2ecf20Sopenharmony_ci	if (!args.started) {
22688c2ecf20Sopenharmony_ci		pr_err("Kernel symbol lookup: ");
22698c2ecf20Sopenharmony_ci		return sym_not_found_error(sym_name, idx);
22708c2ecf20Sopenharmony_ci	}
22718c2ecf20Sopenharmony_ci
22728c2ecf20Sopenharmony_ci	*start = args.start;
22738c2ecf20Sopenharmony_ci	*size = args.size;
22748c2ecf20Sopenharmony_ci
22758c2ecf20Sopenharmony_ci	return 0;
22768c2ecf20Sopenharmony_ci}
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_cistatic int find_entire_kern_cb(void *arg, const char *name __maybe_unused,
22798c2ecf20Sopenharmony_ci			       char type, u64 start)
22808c2ecf20Sopenharmony_ci{
22818c2ecf20Sopenharmony_ci	struct sym_args *args = arg;
22828c2ecf20Sopenharmony_ci	u64 size;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	if (!kallsyms__is_function(type))
22858c2ecf20Sopenharmony_ci		return 0;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	if (!args->started) {
22888c2ecf20Sopenharmony_ci		args->started = true;
22898c2ecf20Sopenharmony_ci		args->start = start;
22908c2ecf20Sopenharmony_ci	}
22918c2ecf20Sopenharmony_ci	/* Don't know exactly where the kernel ends, so we add a page */
22928c2ecf20Sopenharmony_ci	size = round_up(start, page_size) + page_size - args->start;
22938c2ecf20Sopenharmony_ci	if (size > args->size)
22948c2ecf20Sopenharmony_ci		args->size = size;
22958c2ecf20Sopenharmony_ci
22968c2ecf20Sopenharmony_ci	return 0;
22978c2ecf20Sopenharmony_ci}
22988c2ecf20Sopenharmony_ci
22998c2ecf20Sopenharmony_cistatic int addr_filter__entire_kernel(struct addr_filter *filt)
23008c2ecf20Sopenharmony_ci{
23018c2ecf20Sopenharmony_ci	struct sym_args args = { .started = false };
23028c2ecf20Sopenharmony_ci	int err;
23038c2ecf20Sopenharmony_ci
23048c2ecf20Sopenharmony_ci	err = kallsyms__parse("/proc/kallsyms", &args, find_entire_kern_cb);
23058c2ecf20Sopenharmony_ci	if (err < 0 || !args.started) {
23068c2ecf20Sopenharmony_ci		pr_err("Failed to parse /proc/kallsyms\n");
23078c2ecf20Sopenharmony_ci		return err;
23088c2ecf20Sopenharmony_ci	}
23098c2ecf20Sopenharmony_ci
23108c2ecf20Sopenharmony_ci	filt->addr = args.start;
23118c2ecf20Sopenharmony_ci	filt->size = args.size;
23128c2ecf20Sopenharmony_ci
23138c2ecf20Sopenharmony_ci	return 0;
23148c2ecf20Sopenharmony_ci}
23158c2ecf20Sopenharmony_ci
23168c2ecf20Sopenharmony_cistatic int check_end_after_start(struct addr_filter *filt, u64 start, u64 size)
23178c2ecf20Sopenharmony_ci{
23188c2ecf20Sopenharmony_ci	if (start + size >= filt->addr)
23198c2ecf20Sopenharmony_ci		return 0;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci	if (filt->sym_from) {
23228c2ecf20Sopenharmony_ci		pr_err("Symbol '%s' (0x%"PRIx64") comes before '%s' (0x%"PRIx64")\n",
23238c2ecf20Sopenharmony_ci		       filt->sym_to, start, filt->sym_from, filt->addr);
23248c2ecf20Sopenharmony_ci	} else {
23258c2ecf20Sopenharmony_ci		pr_err("Symbol '%s' (0x%"PRIx64") comes before address 0x%"PRIx64")\n",
23268c2ecf20Sopenharmony_ci		       filt->sym_to, start, filt->addr);
23278c2ecf20Sopenharmony_ci	}
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci	return -EINVAL;
23308c2ecf20Sopenharmony_ci}
23318c2ecf20Sopenharmony_ci
23328c2ecf20Sopenharmony_cistatic int addr_filter__resolve_kernel_syms(struct addr_filter *filt)
23338c2ecf20Sopenharmony_ci{
23348c2ecf20Sopenharmony_ci	bool no_size = false;
23358c2ecf20Sopenharmony_ci	u64 start, size;
23368c2ecf20Sopenharmony_ci	int err;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	if (symbol_conf.kptr_restrict) {
23398c2ecf20Sopenharmony_ci		pr_err("Kernel addresses are restricted. Unable to resolve kernel symbols.\n");
23408c2ecf20Sopenharmony_ci		return -EINVAL;
23418c2ecf20Sopenharmony_ci	}
23428c2ecf20Sopenharmony_ci
23438c2ecf20Sopenharmony_ci	if (filt->sym_from && !strcmp(filt->sym_from, "*"))
23448c2ecf20Sopenharmony_ci		return addr_filter__entire_kernel(filt);
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci	if (filt->sym_from) {
23478c2ecf20Sopenharmony_ci		err = find_kern_sym(filt->sym_from, &start, &size,
23488c2ecf20Sopenharmony_ci				    filt->sym_from_idx);
23498c2ecf20Sopenharmony_ci		if (err)
23508c2ecf20Sopenharmony_ci			return err;
23518c2ecf20Sopenharmony_ci		filt->addr = start;
23528c2ecf20Sopenharmony_ci		if (filt->range && !filt->size && !filt->sym_to) {
23538c2ecf20Sopenharmony_ci			filt->size = size;
23548c2ecf20Sopenharmony_ci			no_size = !size;
23558c2ecf20Sopenharmony_ci		}
23568c2ecf20Sopenharmony_ci	}
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci	if (filt->sym_to) {
23598c2ecf20Sopenharmony_ci		err = find_kern_sym(filt->sym_to, &start, &size,
23608c2ecf20Sopenharmony_ci				    filt->sym_to_idx);
23618c2ecf20Sopenharmony_ci		if (err)
23628c2ecf20Sopenharmony_ci			return err;
23638c2ecf20Sopenharmony_ci
23648c2ecf20Sopenharmony_ci		err = check_end_after_start(filt, start, size);
23658c2ecf20Sopenharmony_ci		if (err)
23668c2ecf20Sopenharmony_ci			return err;
23678c2ecf20Sopenharmony_ci		filt->size = start + size - filt->addr;
23688c2ecf20Sopenharmony_ci		no_size = !size;
23698c2ecf20Sopenharmony_ci	}
23708c2ecf20Sopenharmony_ci
23718c2ecf20Sopenharmony_ci	/* The very last symbol in kallsyms does not imply a particular size */
23728c2ecf20Sopenharmony_ci	if (no_size) {
23738c2ecf20Sopenharmony_ci		pr_err("Cannot determine size of symbol '%s'\n",
23748c2ecf20Sopenharmony_ci		       filt->sym_to ? filt->sym_to : filt->sym_from);
23758c2ecf20Sopenharmony_ci		return -EINVAL;
23768c2ecf20Sopenharmony_ci	}
23778c2ecf20Sopenharmony_ci
23788c2ecf20Sopenharmony_ci	return 0;
23798c2ecf20Sopenharmony_ci}
23808c2ecf20Sopenharmony_ci
23818c2ecf20Sopenharmony_cistatic struct dso *load_dso(const char *name)
23828c2ecf20Sopenharmony_ci{
23838c2ecf20Sopenharmony_ci	struct map *map;
23848c2ecf20Sopenharmony_ci	struct dso *dso;
23858c2ecf20Sopenharmony_ci
23868c2ecf20Sopenharmony_ci	map = dso__new_map(name);
23878c2ecf20Sopenharmony_ci	if (!map)
23888c2ecf20Sopenharmony_ci		return NULL;
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci	if (map__load(map) < 0)
23918c2ecf20Sopenharmony_ci		pr_err("File '%s' not found or has no symbols.\n", name);
23928c2ecf20Sopenharmony_ci
23938c2ecf20Sopenharmony_ci	dso = dso__get(map->dso);
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci	map__put(map);
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci	return dso;
23988c2ecf20Sopenharmony_ci}
23998c2ecf20Sopenharmony_ci
24008c2ecf20Sopenharmony_cistatic bool dso_sym_match(struct symbol *sym, const char *name, int *cnt,
24018c2ecf20Sopenharmony_ci			  int idx)
24028c2ecf20Sopenharmony_ci{
24038c2ecf20Sopenharmony_ci	/* Same name, and global or the n'th found or any */
24048c2ecf20Sopenharmony_ci	return !arch__compare_symbol_names(name, sym->name) &&
24058c2ecf20Sopenharmony_ci	       ((!idx && sym->binding == STB_GLOBAL) ||
24068c2ecf20Sopenharmony_ci		(idx > 0 && ++*cnt == idx) ||
24078c2ecf20Sopenharmony_ci		idx < 0);
24088c2ecf20Sopenharmony_ci}
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_cistatic void print_duplicate_syms(struct dso *dso, const char *sym_name)
24118c2ecf20Sopenharmony_ci{
24128c2ecf20Sopenharmony_ci	struct symbol *sym;
24138c2ecf20Sopenharmony_ci	bool near = false;
24148c2ecf20Sopenharmony_ci	int cnt = 0;
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_ci	pr_err("Multiple symbols with name '%s'\n", sym_name);
24178c2ecf20Sopenharmony_ci
24188c2ecf20Sopenharmony_ci	sym = dso__first_symbol(dso);
24198c2ecf20Sopenharmony_ci	while (sym) {
24208c2ecf20Sopenharmony_ci		if (dso_sym_match(sym, sym_name, &cnt, -1)) {
24218c2ecf20Sopenharmony_ci			pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n",
24228c2ecf20Sopenharmony_ci			       ++cnt, sym->start,
24238c2ecf20Sopenharmony_ci			       sym->binding == STB_GLOBAL ? 'g' :
24248c2ecf20Sopenharmony_ci			       sym->binding == STB_LOCAL  ? 'l' : 'w',
24258c2ecf20Sopenharmony_ci			       sym->name);
24268c2ecf20Sopenharmony_ci			near = true;
24278c2ecf20Sopenharmony_ci		} else if (near) {
24288c2ecf20Sopenharmony_ci			near = false;
24298c2ecf20Sopenharmony_ci			pr_err("\t\twhich is near\t\t%s\n", sym->name);
24308c2ecf20Sopenharmony_ci		}
24318c2ecf20Sopenharmony_ci		sym = dso__next_symbol(sym);
24328c2ecf20Sopenharmony_ci	}
24338c2ecf20Sopenharmony_ci
24348c2ecf20Sopenharmony_ci	pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n",
24358c2ecf20Sopenharmony_ci	       sym_name);
24368c2ecf20Sopenharmony_ci	pr_err("Or select a global symbol by inserting #0 or #g or #G\n");
24378c2ecf20Sopenharmony_ci}
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_cistatic int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start,
24408c2ecf20Sopenharmony_ci			u64 *size, int idx)
24418c2ecf20Sopenharmony_ci{
24428c2ecf20Sopenharmony_ci	struct symbol *sym;
24438c2ecf20Sopenharmony_ci	int cnt = 0;
24448c2ecf20Sopenharmony_ci
24458c2ecf20Sopenharmony_ci	*start = 0;
24468c2ecf20Sopenharmony_ci	*size = 0;
24478c2ecf20Sopenharmony_ci
24488c2ecf20Sopenharmony_ci	sym = dso__first_symbol(dso);
24498c2ecf20Sopenharmony_ci	while (sym) {
24508c2ecf20Sopenharmony_ci		if (*start) {
24518c2ecf20Sopenharmony_ci			if (!*size)
24528c2ecf20Sopenharmony_ci				*size = sym->start - *start;
24538c2ecf20Sopenharmony_ci			if (idx > 0) {
24548c2ecf20Sopenharmony_ci				if (*size)
24558c2ecf20Sopenharmony_ci					return 0;
24568c2ecf20Sopenharmony_ci			} else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
24578c2ecf20Sopenharmony_ci				print_duplicate_syms(dso, sym_name);
24588c2ecf20Sopenharmony_ci				return -EINVAL;
24598c2ecf20Sopenharmony_ci			}
24608c2ecf20Sopenharmony_ci		} else if (dso_sym_match(sym, sym_name, &cnt, idx)) {
24618c2ecf20Sopenharmony_ci			*start = sym->start;
24628c2ecf20Sopenharmony_ci			*size = sym->end - sym->start;
24638c2ecf20Sopenharmony_ci		}
24648c2ecf20Sopenharmony_ci		sym = dso__next_symbol(sym);
24658c2ecf20Sopenharmony_ci	}
24668c2ecf20Sopenharmony_ci
24678c2ecf20Sopenharmony_ci	if (!*start)
24688c2ecf20Sopenharmony_ci		return sym_not_found_error(sym_name, idx);
24698c2ecf20Sopenharmony_ci
24708c2ecf20Sopenharmony_ci	return 0;
24718c2ecf20Sopenharmony_ci}
24728c2ecf20Sopenharmony_ci
24738c2ecf20Sopenharmony_cistatic int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso)
24748c2ecf20Sopenharmony_ci{
24758c2ecf20Sopenharmony_ci	if (dso__data_file_size(dso, NULL)) {
24768c2ecf20Sopenharmony_ci		pr_err("Failed to determine filter for %s\nCannot determine file size.\n",
24778c2ecf20Sopenharmony_ci		       filt->filename);
24788c2ecf20Sopenharmony_ci		return -EINVAL;
24798c2ecf20Sopenharmony_ci	}
24808c2ecf20Sopenharmony_ci
24818c2ecf20Sopenharmony_ci	filt->addr = 0;
24828c2ecf20Sopenharmony_ci	filt->size = dso->data.file_size;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	return 0;
24858c2ecf20Sopenharmony_ci}
24868c2ecf20Sopenharmony_ci
24878c2ecf20Sopenharmony_cistatic int addr_filter__resolve_syms(struct addr_filter *filt)
24888c2ecf20Sopenharmony_ci{
24898c2ecf20Sopenharmony_ci	u64 start, size;
24908c2ecf20Sopenharmony_ci	struct dso *dso;
24918c2ecf20Sopenharmony_ci	int err = 0;
24928c2ecf20Sopenharmony_ci
24938c2ecf20Sopenharmony_ci	if (!filt->sym_from && !filt->sym_to)
24948c2ecf20Sopenharmony_ci		return 0;
24958c2ecf20Sopenharmony_ci
24968c2ecf20Sopenharmony_ci	if (!filt->filename)
24978c2ecf20Sopenharmony_ci		return addr_filter__resolve_kernel_syms(filt);
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	dso = load_dso(filt->filename);
25008c2ecf20Sopenharmony_ci	if (!dso) {
25018c2ecf20Sopenharmony_ci		pr_err("Failed to load symbols from: %s\n", filt->filename);
25028c2ecf20Sopenharmony_ci		return -EINVAL;
25038c2ecf20Sopenharmony_ci	}
25048c2ecf20Sopenharmony_ci
25058c2ecf20Sopenharmony_ci	if (filt->sym_from && !strcmp(filt->sym_from, "*")) {
25068c2ecf20Sopenharmony_ci		err = addr_filter__entire_dso(filt, dso);
25078c2ecf20Sopenharmony_ci		goto put_dso;
25088c2ecf20Sopenharmony_ci	}
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci	if (filt->sym_from) {
25118c2ecf20Sopenharmony_ci		err = find_dso_sym(dso, filt->sym_from, &start, &size,
25128c2ecf20Sopenharmony_ci				   filt->sym_from_idx);
25138c2ecf20Sopenharmony_ci		if (err)
25148c2ecf20Sopenharmony_ci			goto put_dso;
25158c2ecf20Sopenharmony_ci		filt->addr = start;
25168c2ecf20Sopenharmony_ci		if (filt->range && !filt->size && !filt->sym_to)
25178c2ecf20Sopenharmony_ci			filt->size = size;
25188c2ecf20Sopenharmony_ci	}
25198c2ecf20Sopenharmony_ci
25208c2ecf20Sopenharmony_ci	if (filt->sym_to) {
25218c2ecf20Sopenharmony_ci		err = find_dso_sym(dso, filt->sym_to, &start, &size,
25228c2ecf20Sopenharmony_ci				   filt->sym_to_idx);
25238c2ecf20Sopenharmony_ci		if (err)
25248c2ecf20Sopenharmony_ci			goto put_dso;
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci		err = check_end_after_start(filt, start, size);
25278c2ecf20Sopenharmony_ci		if (err)
25288c2ecf20Sopenharmony_ci			return err;
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci		filt->size = start + size - filt->addr;
25318c2ecf20Sopenharmony_ci	}
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ciput_dso:
25348c2ecf20Sopenharmony_ci	dso__put(dso);
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	return err;
25378c2ecf20Sopenharmony_ci}
25388c2ecf20Sopenharmony_ci
25398c2ecf20Sopenharmony_cistatic char *addr_filter__to_str(struct addr_filter *filt)
25408c2ecf20Sopenharmony_ci{
25418c2ecf20Sopenharmony_ci	char filename_buf[PATH_MAX];
25428c2ecf20Sopenharmony_ci	const char *at = "";
25438c2ecf20Sopenharmony_ci	const char *fn = "";
25448c2ecf20Sopenharmony_ci	char *filter;
25458c2ecf20Sopenharmony_ci	int err;
25468c2ecf20Sopenharmony_ci
25478c2ecf20Sopenharmony_ci	if (filt->filename) {
25488c2ecf20Sopenharmony_ci		at = "@";
25498c2ecf20Sopenharmony_ci		fn = realpath(filt->filename, filename_buf);
25508c2ecf20Sopenharmony_ci		if (!fn)
25518c2ecf20Sopenharmony_ci			return NULL;
25528c2ecf20Sopenharmony_ci	}
25538c2ecf20Sopenharmony_ci
25548c2ecf20Sopenharmony_ci	if (filt->range) {
25558c2ecf20Sopenharmony_ci		err = asprintf(&filter, "%s 0x%"PRIx64"/0x%"PRIx64"%s%s",
25568c2ecf20Sopenharmony_ci			       filt->action, filt->addr, filt->size, at, fn);
25578c2ecf20Sopenharmony_ci	} else {
25588c2ecf20Sopenharmony_ci		err = asprintf(&filter, "%s 0x%"PRIx64"%s%s",
25598c2ecf20Sopenharmony_ci			       filt->action, filt->addr, at, fn);
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	return err < 0 ? NULL : filter;
25638c2ecf20Sopenharmony_ci}
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_cistatic int parse_addr_filter(struct evsel *evsel, const char *filter,
25668c2ecf20Sopenharmony_ci			     int max_nr)
25678c2ecf20Sopenharmony_ci{
25688c2ecf20Sopenharmony_ci	struct addr_filters filts;
25698c2ecf20Sopenharmony_ci	struct addr_filter *filt;
25708c2ecf20Sopenharmony_ci	int err;
25718c2ecf20Sopenharmony_ci
25728c2ecf20Sopenharmony_ci	addr_filters__init(&filts);
25738c2ecf20Sopenharmony_ci
25748c2ecf20Sopenharmony_ci	err = addr_filters__parse_bare_filter(&filts, filter);
25758c2ecf20Sopenharmony_ci	if (err)
25768c2ecf20Sopenharmony_ci		goto out_exit;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	if (filts.cnt > max_nr) {
25798c2ecf20Sopenharmony_ci		pr_err("Error: number of address filters (%d) exceeds maximum (%d)\n",
25808c2ecf20Sopenharmony_ci		       filts.cnt, max_nr);
25818c2ecf20Sopenharmony_ci		err = -EINVAL;
25828c2ecf20Sopenharmony_ci		goto out_exit;
25838c2ecf20Sopenharmony_ci	}
25848c2ecf20Sopenharmony_ci
25858c2ecf20Sopenharmony_ci	list_for_each_entry(filt, &filts.head, list) {
25868c2ecf20Sopenharmony_ci		char *new_filter;
25878c2ecf20Sopenharmony_ci
25888c2ecf20Sopenharmony_ci		err = addr_filter__resolve_syms(filt);
25898c2ecf20Sopenharmony_ci		if (err)
25908c2ecf20Sopenharmony_ci			goto out_exit;
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci		new_filter = addr_filter__to_str(filt);
25938c2ecf20Sopenharmony_ci		if (!new_filter) {
25948c2ecf20Sopenharmony_ci			err = -ENOMEM;
25958c2ecf20Sopenharmony_ci			goto out_exit;
25968c2ecf20Sopenharmony_ci		}
25978c2ecf20Sopenharmony_ci
25988c2ecf20Sopenharmony_ci		if (evsel__append_addr_filter(evsel, new_filter)) {
25998c2ecf20Sopenharmony_ci			err = -ENOMEM;
26008c2ecf20Sopenharmony_ci			goto out_exit;
26018c2ecf20Sopenharmony_ci		}
26028c2ecf20Sopenharmony_ci	}
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ciout_exit:
26058c2ecf20Sopenharmony_ci	addr_filters__exit(&filts);
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	if (err) {
26088c2ecf20Sopenharmony_ci		pr_err("Failed to parse address filter: '%s'\n", filter);
26098c2ecf20Sopenharmony_ci		pr_err("Filter format is: filter|start|stop|tracestop <start symbol or address> [/ <end symbol or size>] [@<file name>]\n");
26108c2ecf20Sopenharmony_ci		pr_err("Where multiple filters are separated by space or comma.\n");
26118c2ecf20Sopenharmony_ci	}
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci	return err;
26148c2ecf20Sopenharmony_ci}
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_cistatic int evsel__nr_addr_filter(struct evsel *evsel)
26178c2ecf20Sopenharmony_ci{
26188c2ecf20Sopenharmony_ci	struct perf_pmu *pmu = evsel__find_pmu(evsel);
26198c2ecf20Sopenharmony_ci	int nr_addr_filters = 0;
26208c2ecf20Sopenharmony_ci
26218c2ecf20Sopenharmony_ci	if (!pmu)
26228c2ecf20Sopenharmony_ci		return 0;
26238c2ecf20Sopenharmony_ci
26248c2ecf20Sopenharmony_ci	perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters);
26258c2ecf20Sopenharmony_ci
26268c2ecf20Sopenharmony_ci	return nr_addr_filters;
26278c2ecf20Sopenharmony_ci}
26288c2ecf20Sopenharmony_ci
26298c2ecf20Sopenharmony_ciint auxtrace_parse_filters(struct evlist *evlist)
26308c2ecf20Sopenharmony_ci{
26318c2ecf20Sopenharmony_ci	struct evsel *evsel;
26328c2ecf20Sopenharmony_ci	char *filter;
26338c2ecf20Sopenharmony_ci	int err, max_nr;
26348c2ecf20Sopenharmony_ci
26358c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
26368c2ecf20Sopenharmony_ci		filter = evsel->filter;
26378c2ecf20Sopenharmony_ci		max_nr = evsel__nr_addr_filter(evsel);
26388c2ecf20Sopenharmony_ci		if (!filter || !max_nr)
26398c2ecf20Sopenharmony_ci			continue;
26408c2ecf20Sopenharmony_ci		evsel->filter = NULL;
26418c2ecf20Sopenharmony_ci		err = parse_addr_filter(evsel, filter, max_nr);
26428c2ecf20Sopenharmony_ci		free(filter);
26438c2ecf20Sopenharmony_ci		if (err)
26448c2ecf20Sopenharmony_ci			return err;
26458c2ecf20Sopenharmony_ci		pr_debug("Address filter: %s\n", evsel->filter);
26468c2ecf20Sopenharmony_ci	}
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci	return 0;
26498c2ecf20Sopenharmony_ci}
26508c2ecf20Sopenharmony_ci
26518c2ecf20Sopenharmony_ciint auxtrace__process_event(struct perf_session *session, union perf_event *event,
26528c2ecf20Sopenharmony_ci			    struct perf_sample *sample, struct perf_tool *tool)
26538c2ecf20Sopenharmony_ci{
26548c2ecf20Sopenharmony_ci	if (!session->auxtrace)
26558c2ecf20Sopenharmony_ci		return 0;
26568c2ecf20Sopenharmony_ci
26578c2ecf20Sopenharmony_ci	return session->auxtrace->process_event(session, event, sample, tool);
26588c2ecf20Sopenharmony_ci}
26598c2ecf20Sopenharmony_ci
26608c2ecf20Sopenharmony_civoid auxtrace__dump_auxtrace_sample(struct perf_session *session,
26618c2ecf20Sopenharmony_ci				    struct perf_sample *sample)
26628c2ecf20Sopenharmony_ci{
26638c2ecf20Sopenharmony_ci	if (!session->auxtrace || !session->auxtrace->dump_auxtrace_sample ||
26648c2ecf20Sopenharmony_ci	    auxtrace__dont_decode(session))
26658c2ecf20Sopenharmony_ci		return;
26668c2ecf20Sopenharmony_ci
26678c2ecf20Sopenharmony_ci	session->auxtrace->dump_auxtrace_sample(session, sample);
26688c2ecf20Sopenharmony_ci}
26698c2ecf20Sopenharmony_ci
26708c2ecf20Sopenharmony_ciint auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool)
26718c2ecf20Sopenharmony_ci{
26728c2ecf20Sopenharmony_ci	if (!session->auxtrace)
26738c2ecf20Sopenharmony_ci		return 0;
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci	return session->auxtrace->flush_events(session, tool);
26768c2ecf20Sopenharmony_ci}
26778c2ecf20Sopenharmony_ci
26788c2ecf20Sopenharmony_civoid auxtrace__free_events(struct perf_session *session)
26798c2ecf20Sopenharmony_ci{
26808c2ecf20Sopenharmony_ci	if (!session->auxtrace)
26818c2ecf20Sopenharmony_ci		return;
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci	return session->auxtrace->free_events(session);
26848c2ecf20Sopenharmony_ci}
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_civoid auxtrace__free(struct perf_session *session)
26878c2ecf20Sopenharmony_ci{
26888c2ecf20Sopenharmony_ci	if (!session->auxtrace)
26898c2ecf20Sopenharmony_ci		return;
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci	return session->auxtrace->free(session);
26928c2ecf20Sopenharmony_ci}
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_cibool auxtrace__evsel_is_auxtrace(struct perf_session *session,
26958c2ecf20Sopenharmony_ci				 struct evsel *evsel)
26968c2ecf20Sopenharmony_ci{
26978c2ecf20Sopenharmony_ci	if (!session->auxtrace || !session->auxtrace->evsel_is_auxtrace)
26988c2ecf20Sopenharmony_ci		return false;
26998c2ecf20Sopenharmony_ci
27008c2ecf20Sopenharmony_ci	return session->auxtrace->evsel_is_auxtrace(session, evsel);
27018c2ecf20Sopenharmony_ci}
2702