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