12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2718c602dSAdrian Hunter /* 3718c602dSAdrian Hunter * auxtrace.c: AUX area trace support 4718c602dSAdrian Hunter * Copyright (c) 2013-2015, Intel Corporation. 5718c602dSAdrian Hunter */ 6718c602dSAdrian Hunter 7fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 8718c602dSAdrian Hunter #include <sys/types.h> 9718c602dSAdrian Hunter #include <sys/mman.h> 10718c602dSAdrian Hunter #include <stdbool.h> 111b36c03eSAdrian Hunter #include <string.h> 121b36c03eSAdrian Hunter #include <limits.h> 131b36c03eSAdrian Hunter #include <errno.h> 14718c602dSAdrian Hunter 15718c602dSAdrian Hunter #include <linux/kernel.h> 16718c602dSAdrian Hunter #include <linux/perf_event.h> 17718c602dSAdrian Hunter #include <linux/types.h> 18718c602dSAdrian Hunter #include <linux/bitops.h> 19718c602dSAdrian Hunter #include <linux/log2.h> 20e5027893SAdrian Hunter #include <linux/string.h> 2116bd4321SAdrian Hunter #include <linux/time64.h> 22718c602dSAdrian Hunter 23e5027893SAdrian Hunter #include <sys/param.h> 249e0cc4feSAdrian Hunter #include <stdlib.h> 2585ed4729SAdrian Hunter #include <stdio.h> 26e5027893SAdrian Hunter #include <linux/list.h> 277f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 289e0cc4feSAdrian Hunter 29a7fdd30aSAdrian Hunter #include "config.h" 30718c602dSAdrian Hunter #include "evlist.h" 311b36c03eSAdrian Hunter #include "dso.h" 321b36c03eSAdrian Hunter #include "map.h" 331b36c03eSAdrian Hunter #include "pmu.h" 341b36c03eSAdrian Hunter #include "evsel.h" 35eb7a52d4SAdrian Hunter #include "evsel_config.h" 367cadca8eSArnaldo Carvalho de Melo #include "symbol.h" 3740c7d246SArnaldo Carvalho de Melo #include "util/perf_api_probe.h" 38ea49e01cSArnaldo Carvalho de Melo #include "util/synthetic-events.h" 39718c602dSAdrian Hunter #include "thread_map.h" 40718c602dSAdrian Hunter #include "asm/bug.h" 41718c602dSAdrian Hunter #include "auxtrace.h" 42718c602dSAdrian Hunter 43c3278f02SAdrian Hunter #include <linux/hash.h> 44c3278f02SAdrian Hunter 459e0cc4feSAdrian Hunter #include "event.h" 46aeb00b1aSArnaldo Carvalho de Melo #include "record.h" 4785ed4729SAdrian Hunter #include "session.h" 489e0cc4feSAdrian Hunter #include "debug.h" 494b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 509e0cc4feSAdrian Hunter 51440a23b3SMathieu Poirier #include "cs-etm.h" 525efb1d54SAdrian Hunter #include "intel-pt.h" 53d0170af7SAdrian Hunter #include "intel-bts.h" 54ffd3d18cSKim Phillips #include "arm-spe.h" 555e91e57eSQi Liu #include "hisi-ptt.h" 56b96e6615SThomas Richter #include "s390-cpumsf.h" 57e0fcfb08SArnaldo Carvalho de Melo #include "util/mmap.h" 585efb1d54SAdrian Hunter 593052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 603d689ed6SArnaldo Carvalho de Melo #include "symbol/kallsyms.h" 61fb71c86cSArnaldo Carvalho de Melo #include <internal/lib.h> 629823147dSArnaldo Carvalho de Melo #include "util/sample.h" 633d689ed6SArnaldo Carvalho de Melo 64eb7a52d4SAdrian Hunter /* 65eb7a52d4SAdrian Hunter * Make a group from 'leader' to 'last', requiring that the events were not 66eb7a52d4SAdrian Hunter * already grouped to a different leader. 67eb7a52d4SAdrian Hunter */ 6864b4778bSArnaldo Carvalho de Melo static int evlist__regroup(struct evlist *evlist, struct evsel *leader, struct evsel *last) 69eb7a52d4SAdrian Hunter { 70eb7a52d4SAdrian Hunter struct evsel *evsel; 71eb7a52d4SAdrian Hunter bool grp; 72eb7a52d4SAdrian Hunter 73c754c382SArnaldo Carvalho de Melo if (!evsel__is_group_leader(leader)) 74eb7a52d4SAdrian Hunter return -EINVAL; 75eb7a52d4SAdrian Hunter 76eb7a52d4SAdrian Hunter grp = false; 77eb7a52d4SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 78eb7a52d4SAdrian Hunter if (grp) { 79fba7c866SJiri Olsa if (!(evsel__leader(evsel) == leader || 80fba7c866SJiri Olsa (evsel__leader(evsel) == evsel && 81eb7a52d4SAdrian Hunter evsel->core.nr_members <= 1))) 82eb7a52d4SAdrian Hunter return -EINVAL; 83eb7a52d4SAdrian Hunter } else if (evsel == leader) { 84eb7a52d4SAdrian Hunter grp = true; 85eb7a52d4SAdrian Hunter } 86eb7a52d4SAdrian Hunter if (evsel == last) 87eb7a52d4SAdrian Hunter break; 88eb7a52d4SAdrian Hunter } 89eb7a52d4SAdrian Hunter 90eb7a52d4SAdrian Hunter grp = false; 91eb7a52d4SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 92eb7a52d4SAdrian Hunter if (grp) { 93fba7c866SJiri Olsa if (!evsel__has_leader(evsel, leader)) { 94fba7c866SJiri Olsa evsel__set_leader(evsel, leader); 95eb7a52d4SAdrian Hunter if (leader->core.nr_members < 1) 96eb7a52d4SAdrian Hunter leader->core.nr_members = 1; 97eb7a52d4SAdrian Hunter leader->core.nr_members += 1; 98eb7a52d4SAdrian Hunter } 99eb7a52d4SAdrian Hunter } else if (evsel == leader) { 100eb7a52d4SAdrian Hunter grp = true; 101eb7a52d4SAdrian Hunter } 102eb7a52d4SAdrian Hunter if (evsel == last) 103eb7a52d4SAdrian Hunter break; 104eb7a52d4SAdrian Hunter } 105eb7a52d4SAdrian Hunter 106eb7a52d4SAdrian Hunter return 0; 107eb7a52d4SAdrian Hunter } 108eb7a52d4SAdrian Hunter 1092e2967f4SAdrian Hunter static bool auxtrace__dont_decode(struct perf_session *session) 1102e2967f4SAdrian Hunter { 1112e2967f4SAdrian Hunter return !session->itrace_synth_opts || 1122e2967f4SAdrian Hunter session->itrace_synth_opts->dont_decode; 1132e2967f4SAdrian Hunter } 1142e2967f4SAdrian Hunter 115718c602dSAdrian Hunter int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, 116718c602dSAdrian Hunter struct auxtrace_mmap_params *mp, 117718c602dSAdrian Hunter void *userpg, int fd) 118718c602dSAdrian Hunter { 119718c602dSAdrian Hunter struct perf_event_mmap_page *pc = userpg; 120718c602dSAdrian Hunter 121718c602dSAdrian Hunter WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n"); 122718c602dSAdrian Hunter 123718c602dSAdrian Hunter mm->userpg = userpg; 124718c602dSAdrian Hunter mm->mask = mp->mask; 125718c602dSAdrian Hunter mm->len = mp->len; 126718c602dSAdrian Hunter mm->prev = 0; 127718c602dSAdrian Hunter mm->idx = mp->idx; 128718c602dSAdrian Hunter mm->tid = mp->tid; 1296d18804bSIan Rogers mm->cpu = mp->cpu.cpu; 130718c602dSAdrian Hunter 131d01508f2SAdrian Hunter if (!mp->len || !mp->mmap_needed) { 132718c602dSAdrian Hunter mm->base = NULL; 133718c602dSAdrian Hunter return 0; 134718c602dSAdrian Hunter } 135718c602dSAdrian Hunter 136718c602dSAdrian Hunter pc->aux_offset = mp->offset; 137718c602dSAdrian Hunter pc->aux_size = mp->len; 138718c602dSAdrian Hunter 139718c602dSAdrian Hunter mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset); 140718c602dSAdrian Hunter if (mm->base == MAP_FAILED) { 141718c602dSAdrian Hunter pr_debug2("failed to mmap AUX area\n"); 142718c602dSAdrian Hunter mm->base = NULL; 143718c602dSAdrian Hunter return -1; 144718c602dSAdrian Hunter } 145718c602dSAdrian Hunter 146718c602dSAdrian Hunter return 0; 147718c602dSAdrian Hunter } 148718c602dSAdrian Hunter 149718c602dSAdrian Hunter void auxtrace_mmap__munmap(struct auxtrace_mmap *mm) 150718c602dSAdrian Hunter { 151718c602dSAdrian Hunter if (mm->base) { 152718c602dSAdrian Hunter munmap(mm->base, mm->len); 153718c602dSAdrian Hunter mm->base = NULL; 154718c602dSAdrian Hunter } 155718c602dSAdrian Hunter } 156718c602dSAdrian Hunter 157718c602dSAdrian Hunter void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, 158718c602dSAdrian Hunter off_t auxtrace_offset, 159718c602dSAdrian Hunter unsigned int auxtrace_pages, 160718c602dSAdrian Hunter bool auxtrace_overwrite) 161718c602dSAdrian Hunter { 162718c602dSAdrian Hunter if (auxtrace_pages) { 163718c602dSAdrian Hunter mp->offset = auxtrace_offset; 164718c602dSAdrian Hunter mp->len = auxtrace_pages * (size_t)page_size; 165718c602dSAdrian Hunter mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0; 166718c602dSAdrian Hunter mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE); 167718c602dSAdrian Hunter pr_debug2("AUX area mmap length %zu\n", mp->len); 168718c602dSAdrian Hunter } else { 169718c602dSAdrian Hunter mp->len = 0; 170718c602dSAdrian Hunter } 171718c602dSAdrian Hunter } 172718c602dSAdrian Hunter 173718c602dSAdrian Hunter void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, 174d01508f2SAdrian Hunter struct evlist *evlist, 17584bd5abaSAdrian Hunter struct evsel *evsel, int idx) 176718c602dSAdrian Hunter { 1773e5deb70SIan Rogers bool per_cpu = !perf_cpu_map__has_any_cpu(evlist->core.user_requested_cpus); 17884bd5abaSAdrian Hunter 179d01508f2SAdrian Hunter mp->mmap_needed = evsel->needs_auxtrace_mmap; 180d01508f2SAdrian Hunter 181d01508f2SAdrian Hunter if (!mp->mmap_needed) 182d01508f2SAdrian Hunter return; 183d01508f2SAdrian Hunter 184718c602dSAdrian Hunter mp->idx = idx; 185718c602dSAdrian Hunter 186718c602dSAdrian Hunter if (per_cpu) { 1877be1feddSAdrian Hunter mp->cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); 18803617c22SJiri Olsa if (evlist->core.threads) 189a2f354e3SJiri Olsa mp->tid = perf_thread_map__pid(evlist->core.threads, 0); 190718c602dSAdrian Hunter else 191718c602dSAdrian Hunter mp->tid = -1; 192718c602dSAdrian Hunter } else { 1936d18804bSIan Rogers mp->cpu.cpu = -1; 194a2f354e3SJiri Olsa mp->tid = perf_thread_map__pid(evlist->core.threads, idx); 195718c602dSAdrian Hunter } 196718c602dSAdrian Hunter } 1979e0cc4feSAdrian Hunter 198e5027893SAdrian Hunter #define AUXTRACE_INIT_NR_QUEUES 32 199e5027893SAdrian Hunter 200e5027893SAdrian Hunter static struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues) 201e5027893SAdrian Hunter { 202e5027893SAdrian Hunter struct auxtrace_queue *queue_array; 203e5027893SAdrian Hunter unsigned int max_nr_queues, i; 204e5027893SAdrian Hunter 205e5027893SAdrian Hunter max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue); 206e5027893SAdrian Hunter if (nr_queues > max_nr_queues) 207e5027893SAdrian Hunter return NULL; 208e5027893SAdrian Hunter 209e5027893SAdrian Hunter queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue)); 210e5027893SAdrian Hunter if (!queue_array) 211e5027893SAdrian Hunter return NULL; 212e5027893SAdrian Hunter 213e5027893SAdrian Hunter for (i = 0; i < nr_queues; i++) { 214e5027893SAdrian Hunter INIT_LIST_HEAD(&queue_array[i].head); 215e5027893SAdrian Hunter queue_array[i].priv = NULL; 216e5027893SAdrian Hunter } 217e5027893SAdrian Hunter 218e5027893SAdrian Hunter return queue_array; 219e5027893SAdrian Hunter } 220e5027893SAdrian Hunter 221*ee73fe99SJames Clark int auxtrace_queues__init_nr(struct auxtrace_queues *queues, int nr_queues) 222e5027893SAdrian Hunter { 223*ee73fe99SJames Clark queues->nr_queues = nr_queues; 224e5027893SAdrian Hunter queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues); 225e5027893SAdrian Hunter if (!queues->queue_array) 226e5027893SAdrian Hunter return -ENOMEM; 227e5027893SAdrian Hunter return 0; 228e5027893SAdrian Hunter } 229e5027893SAdrian Hunter 230*ee73fe99SJames Clark int auxtrace_queues__init(struct auxtrace_queues *queues) 231*ee73fe99SJames Clark { 232*ee73fe99SJames Clark return auxtrace_queues__init_nr(queues, AUXTRACE_INIT_NR_QUEUES); 233*ee73fe99SJames Clark } 234*ee73fe99SJames Clark 235e5027893SAdrian Hunter static int auxtrace_queues__grow(struct auxtrace_queues *queues, 236e5027893SAdrian Hunter unsigned int new_nr_queues) 237e5027893SAdrian Hunter { 238e5027893SAdrian Hunter unsigned int nr_queues = queues->nr_queues; 239e5027893SAdrian Hunter struct auxtrace_queue *queue_array; 240e5027893SAdrian Hunter unsigned int i; 241e5027893SAdrian Hunter 242e5027893SAdrian Hunter if (!nr_queues) 243e5027893SAdrian Hunter nr_queues = AUXTRACE_INIT_NR_QUEUES; 244e5027893SAdrian Hunter 245e5027893SAdrian Hunter while (nr_queues && nr_queues < new_nr_queues) 246e5027893SAdrian Hunter nr_queues <<= 1; 247e5027893SAdrian Hunter 248e5027893SAdrian Hunter if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues) 249e5027893SAdrian Hunter return -EINVAL; 250e5027893SAdrian Hunter 251e5027893SAdrian Hunter queue_array = auxtrace_alloc_queue_array(nr_queues); 252e5027893SAdrian Hunter if (!queue_array) 253e5027893SAdrian Hunter return -ENOMEM; 254e5027893SAdrian Hunter 255e5027893SAdrian Hunter for (i = 0; i < queues->nr_queues; i++) { 256e5027893SAdrian Hunter list_splice_tail(&queues->queue_array[i].head, 257e5027893SAdrian Hunter &queue_array[i].head); 25899cbbe56SAdrian Hunter queue_array[i].tid = queues->queue_array[i].tid; 25999cbbe56SAdrian Hunter queue_array[i].cpu = queues->queue_array[i].cpu; 26099cbbe56SAdrian Hunter queue_array[i].set = queues->queue_array[i].set; 261e5027893SAdrian Hunter queue_array[i].priv = queues->queue_array[i].priv; 262e5027893SAdrian Hunter } 263e5027893SAdrian Hunter 264e5027893SAdrian Hunter queues->nr_queues = nr_queues; 265e5027893SAdrian Hunter queues->queue_array = queue_array; 266e5027893SAdrian Hunter 267e5027893SAdrian Hunter return 0; 268e5027893SAdrian Hunter } 269e5027893SAdrian Hunter 270e5027893SAdrian Hunter static void *auxtrace_copy_data(u64 size, struct perf_session *session) 271e5027893SAdrian Hunter { 2728ceb41d7SJiri Olsa int fd = perf_data__fd(session->data); 273e5027893SAdrian Hunter void *p; 274e5027893SAdrian Hunter ssize_t ret; 275e5027893SAdrian Hunter 276e5027893SAdrian Hunter if (size > SSIZE_MAX) 277e5027893SAdrian Hunter return NULL; 278e5027893SAdrian Hunter 279e5027893SAdrian Hunter p = malloc(size); 280e5027893SAdrian Hunter if (!p) 281e5027893SAdrian Hunter return NULL; 282e5027893SAdrian Hunter 283e5027893SAdrian Hunter ret = readn(fd, p, size); 284e5027893SAdrian Hunter if (ret != (ssize_t)size) { 285e5027893SAdrian Hunter free(p); 286e5027893SAdrian Hunter return NULL; 287e5027893SAdrian Hunter } 288e5027893SAdrian Hunter 289e5027893SAdrian Hunter return p; 290e5027893SAdrian Hunter } 291e5027893SAdrian Hunter 292a356a597SAdrian Hunter static int auxtrace_queues__queue_buffer(struct auxtrace_queues *queues, 293e5027893SAdrian Hunter unsigned int idx, 294e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 295e5027893SAdrian Hunter { 296e5027893SAdrian Hunter struct auxtrace_queue *queue; 297e5027893SAdrian Hunter int err; 298e5027893SAdrian Hunter 299e5027893SAdrian Hunter if (idx >= queues->nr_queues) { 300e5027893SAdrian Hunter err = auxtrace_queues__grow(queues, idx + 1); 301e5027893SAdrian Hunter if (err) 302e5027893SAdrian Hunter return err; 303e5027893SAdrian Hunter } 304e5027893SAdrian Hunter 305e5027893SAdrian Hunter queue = &queues->queue_array[idx]; 306e5027893SAdrian Hunter 307e5027893SAdrian Hunter if (!queue->set) { 308e5027893SAdrian Hunter queue->set = true; 309e5027893SAdrian Hunter queue->tid = buffer->tid; 3106d18804bSIan Rogers queue->cpu = buffer->cpu.cpu; 311e5027893SAdrian Hunter } 312e5027893SAdrian Hunter 313e5027893SAdrian Hunter buffer->buffer_nr = queues->next_buffer_nr++; 314e5027893SAdrian Hunter 315e5027893SAdrian Hunter list_add_tail(&buffer->list, &queue->head); 316e5027893SAdrian Hunter 317e5027893SAdrian Hunter queues->new_data = true; 318e5027893SAdrian Hunter queues->populated = true; 319e5027893SAdrian Hunter 320e5027893SAdrian Hunter return 0; 321e5027893SAdrian Hunter } 322e5027893SAdrian Hunter 323e5027893SAdrian Hunter /* Limit buffers to 32MiB on 32-bit */ 324e5027893SAdrian Hunter #define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024) 325e5027893SAdrian Hunter 326e5027893SAdrian Hunter static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues, 327e5027893SAdrian Hunter unsigned int idx, 328e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 329e5027893SAdrian Hunter { 330e5027893SAdrian Hunter u64 sz = buffer->size; 331e5027893SAdrian Hunter bool consecutive = false; 332e5027893SAdrian Hunter struct auxtrace_buffer *b; 333e5027893SAdrian Hunter int err; 334e5027893SAdrian Hunter 335e5027893SAdrian Hunter while (sz > BUFFER_LIMIT_FOR_32_BIT) { 336e5027893SAdrian Hunter b = memdup(buffer, sizeof(struct auxtrace_buffer)); 337e5027893SAdrian Hunter if (!b) 338e5027893SAdrian Hunter return -ENOMEM; 339e5027893SAdrian Hunter b->size = BUFFER_LIMIT_FOR_32_BIT; 340e5027893SAdrian Hunter b->consecutive = consecutive; 341a356a597SAdrian Hunter err = auxtrace_queues__queue_buffer(queues, idx, b); 342e5027893SAdrian Hunter if (err) { 343e5027893SAdrian Hunter auxtrace_buffer__free(b); 344e5027893SAdrian Hunter return err; 345e5027893SAdrian Hunter } 346e5027893SAdrian Hunter buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT; 347e5027893SAdrian Hunter sz -= BUFFER_LIMIT_FOR_32_BIT; 348e5027893SAdrian Hunter consecutive = true; 349e5027893SAdrian Hunter } 350e5027893SAdrian Hunter 351e5027893SAdrian Hunter buffer->size = sz; 352e5027893SAdrian Hunter buffer->consecutive = consecutive; 353e5027893SAdrian Hunter 354e5027893SAdrian Hunter return 0; 355e5027893SAdrian Hunter } 356e5027893SAdrian Hunter 3576d18804bSIan Rogers static bool filter_cpu(struct perf_session *session, struct perf_cpu cpu) 358b238db65SAdrian Hunter { 359b238db65SAdrian Hunter unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; 360b238db65SAdrian Hunter 3616d18804bSIan Rogers return cpu_bitmap && cpu.cpu != -1 && !test_bit(cpu.cpu, cpu_bitmap); 362b238db65SAdrian Hunter } 363b238db65SAdrian Hunter 364a356a597SAdrian Hunter static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, 365e5027893SAdrian Hunter struct perf_session *session, 366e5027893SAdrian Hunter unsigned int idx, 3674c454843SAdrian Hunter struct auxtrace_buffer *buffer, 3684c454843SAdrian Hunter struct auxtrace_buffer **buffer_ptr) 369e5027893SAdrian Hunter { 3700d75f123SAdrian Hunter int err = -ENOMEM; 3710d75f123SAdrian Hunter 372b238db65SAdrian Hunter if (filter_cpu(session, buffer->cpu)) 373b238db65SAdrian Hunter return 0; 374b238db65SAdrian Hunter 3750d75f123SAdrian Hunter buffer = memdup(buffer, sizeof(*buffer)); 3760d75f123SAdrian Hunter if (!buffer) 3770d75f123SAdrian Hunter return -ENOMEM; 3784c454843SAdrian Hunter 379e5027893SAdrian Hunter if (session->one_mmap) { 380e5027893SAdrian Hunter buffer->data = buffer->data_offset - session->one_mmap_offset + 381e5027893SAdrian Hunter session->one_mmap_addr; 3828ceb41d7SJiri Olsa } else if (perf_data__is_pipe(session->data)) { 383e5027893SAdrian Hunter buffer->data = auxtrace_copy_data(buffer->size, session); 384e5027893SAdrian Hunter if (!buffer->data) 3850d75f123SAdrian Hunter goto out_free; 386e5027893SAdrian Hunter buffer->data_needs_freeing = true; 387e5027893SAdrian Hunter } else if (BITS_PER_LONG == 32 && 388e5027893SAdrian Hunter buffer->size > BUFFER_LIMIT_FOR_32_BIT) { 389e5027893SAdrian Hunter err = auxtrace_queues__split_buffer(queues, idx, buffer); 390e5027893SAdrian Hunter if (err) 3910d75f123SAdrian Hunter goto out_free; 392e5027893SAdrian Hunter } 393e5027893SAdrian Hunter 3944c454843SAdrian Hunter err = auxtrace_queues__queue_buffer(queues, idx, buffer); 3954c454843SAdrian Hunter if (err) 3960d75f123SAdrian Hunter goto out_free; 3974c454843SAdrian Hunter 3984c454843SAdrian Hunter /* FIXME: Doesn't work for split buffer */ 3994c454843SAdrian Hunter if (buffer_ptr) 4004c454843SAdrian Hunter *buffer_ptr = buffer; 4014c454843SAdrian Hunter 4024c454843SAdrian Hunter return 0; 4030d75f123SAdrian Hunter 4040d75f123SAdrian Hunter out_free: 4050d75f123SAdrian Hunter auxtrace_buffer__free(buffer); 4060d75f123SAdrian Hunter return err; 407e5027893SAdrian Hunter } 408e5027893SAdrian Hunter 409e5027893SAdrian Hunter int auxtrace_queues__add_event(struct auxtrace_queues *queues, 410e5027893SAdrian Hunter struct perf_session *session, 411e5027893SAdrian Hunter union perf_event *event, off_t data_offset, 412e5027893SAdrian Hunter struct auxtrace_buffer **buffer_ptr) 413e5027893SAdrian Hunter { 4140d75f123SAdrian Hunter struct auxtrace_buffer buffer = { 4150d75f123SAdrian Hunter .pid = -1, 4160d75f123SAdrian Hunter .tid = event->auxtrace.tid, 4176d18804bSIan Rogers .cpu = { event->auxtrace.cpu }, 4180d75f123SAdrian Hunter .data_offset = data_offset, 4190d75f123SAdrian Hunter .offset = event->auxtrace.offset, 4200d75f123SAdrian Hunter .reference = event->auxtrace.reference, 4210d75f123SAdrian Hunter .size = event->auxtrace.size, 4220d75f123SAdrian Hunter }; 4230d75f123SAdrian Hunter unsigned int idx = event->auxtrace.idx; 424e5027893SAdrian Hunter 4250d75f123SAdrian Hunter return auxtrace_queues__add_buffer(queues, session, idx, &buffer, 4264c454843SAdrian Hunter buffer_ptr); 427e5027893SAdrian Hunter } 428e5027893SAdrian Hunter 42999fa2984SAdrian Hunter static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, 43099fa2984SAdrian Hunter struct perf_session *session, 43199fa2984SAdrian Hunter off_t file_offset, size_t sz) 43299fa2984SAdrian Hunter { 43399fa2984SAdrian Hunter union perf_event *event; 43499fa2984SAdrian Hunter int err; 43599fa2984SAdrian Hunter char buf[PERF_SAMPLE_MAX_SIZE]; 43699fa2984SAdrian Hunter 43799fa2984SAdrian Hunter err = perf_session__peek_event(session, file_offset, buf, 43899fa2984SAdrian Hunter PERF_SAMPLE_MAX_SIZE, &event, NULL); 43999fa2984SAdrian Hunter if (err) 44099fa2984SAdrian Hunter return err; 44199fa2984SAdrian Hunter 44299fa2984SAdrian Hunter if (event->header.type == PERF_RECORD_AUXTRACE) { 44372932371SJiri Olsa if (event->header.size < sizeof(struct perf_record_auxtrace) || 44499fa2984SAdrian Hunter event->header.size != sz) { 44599fa2984SAdrian Hunter err = -EINVAL; 44699fa2984SAdrian Hunter goto out; 44799fa2984SAdrian Hunter } 44899fa2984SAdrian Hunter file_offset += event->header.size; 44999fa2984SAdrian Hunter err = auxtrace_queues__add_event(queues, session, event, 45099fa2984SAdrian Hunter file_offset, NULL); 45199fa2984SAdrian Hunter } 45299fa2984SAdrian Hunter out: 45399fa2984SAdrian Hunter return err; 45499fa2984SAdrian Hunter } 45599fa2984SAdrian Hunter 456e5027893SAdrian Hunter void auxtrace_queues__free(struct auxtrace_queues *queues) 457e5027893SAdrian Hunter { 458e5027893SAdrian Hunter unsigned int i; 459e5027893SAdrian Hunter 460e5027893SAdrian Hunter for (i = 0; i < queues->nr_queues; i++) { 461e5027893SAdrian Hunter while (!list_empty(&queues->queue_array[i].head)) { 462e5027893SAdrian Hunter struct auxtrace_buffer *buffer; 463e5027893SAdrian Hunter 464e5027893SAdrian Hunter buffer = list_entry(queues->queue_array[i].head.next, 465e5027893SAdrian Hunter struct auxtrace_buffer, list); 466e56fbc9dSArnaldo Carvalho de Melo list_del_init(&buffer->list); 467e5027893SAdrian Hunter auxtrace_buffer__free(buffer); 468e5027893SAdrian Hunter } 469e5027893SAdrian Hunter } 470e5027893SAdrian Hunter 471e5027893SAdrian Hunter zfree(&queues->queue_array); 472e5027893SAdrian Hunter queues->nr_queues = 0; 473e5027893SAdrian Hunter } 474e5027893SAdrian Hunter 475f9397155SAdrian Hunter static void auxtrace_heapify(struct auxtrace_heap_item *heap_array, 476f9397155SAdrian Hunter unsigned int pos, unsigned int queue_nr, 477f9397155SAdrian Hunter u64 ordinal) 478f9397155SAdrian Hunter { 479f9397155SAdrian Hunter unsigned int parent; 480f9397155SAdrian Hunter 481f9397155SAdrian Hunter while (pos) { 482f9397155SAdrian Hunter parent = (pos - 1) >> 1; 483f9397155SAdrian Hunter if (heap_array[parent].ordinal <= ordinal) 484f9397155SAdrian Hunter break; 485f9397155SAdrian Hunter heap_array[pos] = heap_array[parent]; 486f9397155SAdrian Hunter pos = parent; 487f9397155SAdrian Hunter } 488f9397155SAdrian Hunter heap_array[pos].queue_nr = queue_nr; 489f9397155SAdrian Hunter heap_array[pos].ordinal = ordinal; 490f9397155SAdrian Hunter } 491f9397155SAdrian Hunter 492f9397155SAdrian Hunter int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr, 493f9397155SAdrian Hunter u64 ordinal) 494f9397155SAdrian Hunter { 495f9397155SAdrian Hunter struct auxtrace_heap_item *heap_array; 496f9397155SAdrian Hunter 497f9397155SAdrian Hunter if (queue_nr >= heap->heap_sz) { 498f9397155SAdrian Hunter unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES; 499f9397155SAdrian Hunter 500f9397155SAdrian Hunter while (heap_sz <= queue_nr) 501f9397155SAdrian Hunter heap_sz <<= 1; 502f9397155SAdrian Hunter heap_array = realloc(heap->heap_array, 503f9397155SAdrian Hunter heap_sz * sizeof(struct auxtrace_heap_item)); 504f9397155SAdrian Hunter if (!heap_array) 505f9397155SAdrian Hunter return -ENOMEM; 506f9397155SAdrian Hunter heap->heap_array = heap_array; 507f9397155SAdrian Hunter heap->heap_sz = heap_sz; 508f9397155SAdrian Hunter } 509f9397155SAdrian Hunter 510f9397155SAdrian Hunter auxtrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal); 511f9397155SAdrian Hunter 512f9397155SAdrian Hunter return 0; 513f9397155SAdrian Hunter } 514f9397155SAdrian Hunter 515f9397155SAdrian Hunter void auxtrace_heap__free(struct auxtrace_heap *heap) 516f9397155SAdrian Hunter { 517f9397155SAdrian Hunter zfree(&heap->heap_array); 518f9397155SAdrian Hunter heap->heap_cnt = 0; 519f9397155SAdrian Hunter heap->heap_sz = 0; 520f9397155SAdrian Hunter } 521f9397155SAdrian Hunter 522f9397155SAdrian Hunter void auxtrace_heap__pop(struct auxtrace_heap *heap) 523f9397155SAdrian Hunter { 524f9397155SAdrian Hunter unsigned int pos, last, heap_cnt = heap->heap_cnt; 525f9397155SAdrian Hunter struct auxtrace_heap_item *heap_array; 526f9397155SAdrian Hunter 527f9397155SAdrian Hunter if (!heap_cnt) 528f9397155SAdrian Hunter return; 529f9397155SAdrian Hunter 530f9397155SAdrian Hunter heap->heap_cnt -= 1; 531f9397155SAdrian Hunter 532f9397155SAdrian Hunter heap_array = heap->heap_array; 533f9397155SAdrian Hunter 534f9397155SAdrian Hunter pos = 0; 535f9397155SAdrian Hunter while (1) { 536f9397155SAdrian Hunter unsigned int left, right; 537f9397155SAdrian Hunter 538f9397155SAdrian Hunter left = (pos << 1) + 1; 539f9397155SAdrian Hunter if (left >= heap_cnt) 540f9397155SAdrian Hunter break; 541f9397155SAdrian Hunter right = left + 1; 542f9397155SAdrian Hunter if (right >= heap_cnt) { 543f9397155SAdrian Hunter heap_array[pos] = heap_array[left]; 544f9397155SAdrian Hunter return; 545f9397155SAdrian Hunter } 546f9397155SAdrian Hunter if (heap_array[left].ordinal < heap_array[right].ordinal) { 547f9397155SAdrian Hunter heap_array[pos] = heap_array[left]; 548f9397155SAdrian Hunter pos = left; 549f9397155SAdrian Hunter } else { 550f9397155SAdrian Hunter heap_array[pos] = heap_array[right]; 551f9397155SAdrian Hunter pos = right; 552f9397155SAdrian Hunter } 553f9397155SAdrian Hunter } 554f9397155SAdrian Hunter 555f9397155SAdrian Hunter last = heap_cnt - 1; 556f9397155SAdrian Hunter auxtrace_heapify(heap_array, pos, heap_array[last].queue_nr, 557f9397155SAdrian Hunter heap_array[last].ordinal); 558f9397155SAdrian Hunter } 559f9397155SAdrian Hunter 56014a05e13SMathieu Poirier size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, 56163503dbaSJiri Olsa struct evlist *evlist) 5629e0cc4feSAdrian Hunter { 5639e0cc4feSAdrian Hunter if (itr) 56414a05e13SMathieu Poirier return itr->info_priv_size(itr, evlist); 5659e0cc4feSAdrian Hunter return 0; 5669e0cc4feSAdrian Hunter } 5679e0cc4feSAdrian Hunter 5689e0cc4feSAdrian Hunter static int auxtrace_not_supported(void) 5699e0cc4feSAdrian Hunter { 5709e0cc4feSAdrian Hunter pr_err("AUX area tracing is not supported on this architecture\n"); 5719e0cc4feSAdrian Hunter return -EINVAL; 5729e0cc4feSAdrian Hunter } 5739e0cc4feSAdrian Hunter 5749e0cc4feSAdrian Hunter int auxtrace_record__info_fill(struct auxtrace_record *itr, 5759e0cc4feSAdrian Hunter struct perf_session *session, 57672932371SJiri Olsa struct perf_record_auxtrace_info *auxtrace_info, 5779e0cc4feSAdrian Hunter size_t priv_size) 5789e0cc4feSAdrian Hunter { 5799e0cc4feSAdrian Hunter if (itr) 5809e0cc4feSAdrian Hunter return itr->info_fill(itr, session, auxtrace_info, priv_size); 5819e0cc4feSAdrian Hunter return auxtrace_not_supported(); 5829e0cc4feSAdrian Hunter } 5839e0cc4feSAdrian Hunter 5849e0cc4feSAdrian Hunter void auxtrace_record__free(struct auxtrace_record *itr) 5859e0cc4feSAdrian Hunter { 5869e0cc4feSAdrian Hunter if (itr) 5879e0cc4feSAdrian Hunter itr->free(itr); 5889e0cc4feSAdrian Hunter } 5899e0cc4feSAdrian Hunter 590d20031bbSAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr) 591d20031bbSAdrian Hunter { 592d20031bbSAdrian Hunter if (itr && itr->snapshot_start) 593d20031bbSAdrian Hunter return itr->snapshot_start(itr); 594d20031bbSAdrian Hunter return 0; 595d20031bbSAdrian Hunter } 596d20031bbSAdrian Hunter 597ce7b0e42SAlexander Shishkin int auxtrace_record__snapshot_finish(struct auxtrace_record *itr, bool on_exit) 598d20031bbSAdrian Hunter { 599ce7b0e42SAlexander Shishkin if (!on_exit && itr && itr->snapshot_finish) 600d20031bbSAdrian Hunter return itr->snapshot_finish(itr); 601d20031bbSAdrian Hunter return 0; 602d20031bbSAdrian Hunter } 603d20031bbSAdrian Hunter 604d20031bbSAdrian Hunter int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, 605d20031bbSAdrian Hunter struct auxtrace_mmap *mm, 606d20031bbSAdrian Hunter unsigned char *data, u64 *head, u64 *old) 607d20031bbSAdrian Hunter { 608d20031bbSAdrian Hunter if (itr && itr->find_snapshot) 609d20031bbSAdrian Hunter return itr->find_snapshot(itr, idx, mm, data, head, old); 610d20031bbSAdrian Hunter return 0; 611d20031bbSAdrian Hunter } 612d20031bbSAdrian Hunter 6139e0cc4feSAdrian Hunter int auxtrace_record__options(struct auxtrace_record *itr, 61463503dbaSJiri Olsa struct evlist *evlist, 6159e0cc4feSAdrian Hunter struct record_opts *opts) 6169e0cc4feSAdrian Hunter { 617ad60ba0cSAdrian Hunter if (itr) { 618ad60ba0cSAdrian Hunter itr->evlist = evlist; 6199e0cc4feSAdrian Hunter return itr->recording_options(itr, evlist, opts); 620ad60ba0cSAdrian Hunter } 6219e0cc4feSAdrian Hunter return 0; 6229e0cc4feSAdrian Hunter } 6239e0cc4feSAdrian Hunter 6249e0cc4feSAdrian Hunter u64 auxtrace_record__reference(struct auxtrace_record *itr) 6259e0cc4feSAdrian Hunter { 6269e0cc4feSAdrian Hunter if (itr) 6279e0cc4feSAdrian Hunter return itr->reference(itr); 6289e0cc4feSAdrian Hunter return 0; 6299e0cc4feSAdrian Hunter } 6309e0cc4feSAdrian Hunter 631d20031bbSAdrian Hunter int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, 632d20031bbSAdrian Hunter struct record_opts *opts, const char *str) 633d20031bbSAdrian Hunter { 634d20031bbSAdrian Hunter if (!str) 635d20031bbSAdrian Hunter return 0; 636d20031bbSAdrian Hunter 637ce7b0e42SAlexander Shishkin /* PMU-agnostic options */ 638ce7b0e42SAlexander Shishkin switch (*str) { 639ce7b0e42SAlexander Shishkin case 'e': 640ce7b0e42SAlexander Shishkin opts->auxtrace_snapshot_on_exit = true; 641ce7b0e42SAlexander Shishkin str++; 642ce7b0e42SAlexander Shishkin break; 643ce7b0e42SAlexander Shishkin default: 644ce7b0e42SAlexander Shishkin break; 645ce7b0e42SAlexander Shishkin } 646ce7b0e42SAlexander Shishkin 647b14585d9SLeo Yan if (itr && itr->parse_snapshot_options) 648d20031bbSAdrian Hunter return itr->parse_snapshot_options(itr, opts, str); 649d20031bbSAdrian Hunter 650d20031bbSAdrian Hunter pr_err("No AUX area tracing to snapshot\n"); 651d20031bbSAdrian Hunter return -EINVAL; 652d20031bbSAdrian Hunter } 653d20031bbSAdrian Hunter 654024b3b42SAdrian Hunter static int evlist__enable_event_idx(struct evlist *evlist, struct evsel *evsel, int idx) 655024b3b42SAdrian Hunter { 6563e5deb70SIan Rogers bool per_cpu_mmaps = !perf_cpu_map__has_any_cpu(evlist->core.user_requested_cpus); 657024b3b42SAdrian Hunter 658d205a3a6SAdrian Hunter if (per_cpu_mmaps) { 659d205a3a6SAdrian Hunter struct perf_cpu evlist_cpu = perf_cpu_map__cpu(evlist->core.all_cpus, idx); 660d205a3a6SAdrian Hunter int cpu_map_idx = perf_cpu_map__idx(evsel->core.cpus, evlist_cpu); 661d205a3a6SAdrian Hunter 662d205a3a6SAdrian Hunter if (cpu_map_idx == -1) 663d205a3a6SAdrian Hunter return -EINVAL; 664d205a3a6SAdrian Hunter return perf_evsel__enable_cpu(&evsel->core, cpu_map_idx); 665d205a3a6SAdrian Hunter } 666024b3b42SAdrian Hunter 667024b3b42SAdrian Hunter return perf_evsel__enable_thread(&evsel->core, idx); 668024b3b42SAdrian Hunter } 669024b3b42SAdrian Hunter 670ad60ba0cSAdrian Hunter int auxtrace_record__read_finish(struct auxtrace_record *itr, int idx) 671ad60ba0cSAdrian Hunter { 672ad60ba0cSAdrian Hunter struct evsel *evsel; 673ad60ba0cSAdrian Hunter 674ad60ba0cSAdrian Hunter if (!itr->evlist || !itr->pmu) 675ad60ba0cSAdrian Hunter return -EINVAL; 676ad60ba0cSAdrian Hunter 677ad60ba0cSAdrian Hunter evlist__for_each_entry(itr->evlist, evsel) { 678ad60ba0cSAdrian Hunter if (evsel->core.attr.type == itr->pmu->type) { 679ad60ba0cSAdrian Hunter if (evsel->disabled) 680ad60ba0cSAdrian Hunter return 0; 68137b01abeSArnaldo Carvalho de Melo return evlist__enable_event_idx(itr->evlist, evsel, idx); 682ad60ba0cSAdrian Hunter } 683ad60ba0cSAdrian Hunter } 684ad60ba0cSAdrian Hunter return -EINVAL; 685ad60ba0cSAdrian Hunter } 686ad60ba0cSAdrian Hunter 687f0bb7ee8SAdrian Hunter /* 688f0bb7ee8SAdrian Hunter * Event record size is 16-bit which results in a maximum size of about 64KiB. 689f0bb7ee8SAdrian Hunter * Allow about 4KiB for the rest of the sample record, to give a maximum 690f0bb7ee8SAdrian Hunter * AUX area sample size of 60KiB. 691f0bb7ee8SAdrian Hunter */ 692f0bb7ee8SAdrian Hunter #define MAX_AUX_SAMPLE_SIZE (60 * 1024) 693f0bb7ee8SAdrian Hunter 694f0bb7ee8SAdrian Hunter /* Arbitrary default size if no other default provided */ 695f0bb7ee8SAdrian Hunter #define DEFAULT_AUX_SAMPLE_SIZE (4 * 1024) 696f0bb7ee8SAdrian Hunter 697f0bb7ee8SAdrian Hunter static int auxtrace_validate_aux_sample_size(struct evlist *evlist, 698f0bb7ee8SAdrian Hunter struct record_opts *opts) 699f0bb7ee8SAdrian Hunter { 700f0bb7ee8SAdrian Hunter struct evsel *evsel; 701f0bb7ee8SAdrian Hunter bool has_aux_leader = false; 702f0bb7ee8SAdrian Hunter u32 sz; 703f0bb7ee8SAdrian Hunter 704f0bb7ee8SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 705f0bb7ee8SAdrian Hunter sz = evsel->core.attr.aux_sample_size; 706c754c382SArnaldo Carvalho de Melo if (evsel__is_group_leader(evsel)) { 70739453ed5SArnaldo Carvalho de Melo has_aux_leader = evsel__is_aux_event(evsel); 708f0bb7ee8SAdrian Hunter if (sz) { 709f0bb7ee8SAdrian Hunter if (has_aux_leader) 710f0bb7ee8SAdrian Hunter pr_err("Cannot add AUX area sampling to an AUX area event\n"); 711f0bb7ee8SAdrian Hunter else 712f0bb7ee8SAdrian Hunter pr_err("Cannot add AUX area sampling to a group leader\n"); 713f0bb7ee8SAdrian Hunter return -EINVAL; 714f0bb7ee8SAdrian Hunter } 715f0bb7ee8SAdrian Hunter } 716f0bb7ee8SAdrian Hunter if (sz > MAX_AUX_SAMPLE_SIZE) { 717f0bb7ee8SAdrian Hunter pr_err("AUX area sample size %u too big, max. %d\n", 718f0bb7ee8SAdrian Hunter sz, MAX_AUX_SAMPLE_SIZE); 719f0bb7ee8SAdrian Hunter return -EINVAL; 720f0bb7ee8SAdrian Hunter } 721f0bb7ee8SAdrian Hunter if (sz) { 722f0bb7ee8SAdrian Hunter if (!has_aux_leader) { 723f0bb7ee8SAdrian Hunter pr_err("Cannot add AUX area sampling because group leader is not an AUX area event\n"); 724f0bb7ee8SAdrian Hunter return -EINVAL; 725f0bb7ee8SAdrian Hunter } 726862b2f8fSArnaldo Carvalho de Melo evsel__set_sample_bit(evsel, AUX); 727f0bb7ee8SAdrian Hunter opts->auxtrace_sample_mode = true; 728f0bb7ee8SAdrian Hunter } else { 729862b2f8fSArnaldo Carvalho de Melo evsel__reset_sample_bit(evsel, AUX); 730f0bb7ee8SAdrian Hunter } 731f0bb7ee8SAdrian Hunter } 732f0bb7ee8SAdrian Hunter 733f0bb7ee8SAdrian Hunter if (!opts->auxtrace_sample_mode) { 734f0bb7ee8SAdrian Hunter pr_err("AUX area sampling requires an AUX area event group leader plus other events to which to add samples\n"); 735f0bb7ee8SAdrian Hunter return -EINVAL; 736f0bb7ee8SAdrian Hunter } 737f0bb7ee8SAdrian Hunter 738f0bb7ee8SAdrian Hunter if (!perf_can_aux_sample()) { 739f0bb7ee8SAdrian Hunter pr_err("AUX area sampling is not supported by kernel\n"); 740f0bb7ee8SAdrian Hunter return -EINVAL; 741f0bb7ee8SAdrian Hunter } 742f0bb7ee8SAdrian Hunter 743f0bb7ee8SAdrian Hunter return 0; 744f0bb7ee8SAdrian Hunter } 745f0bb7ee8SAdrian Hunter 746f0bb7ee8SAdrian Hunter int auxtrace_parse_sample_options(struct auxtrace_record *itr, 747f0bb7ee8SAdrian Hunter struct evlist *evlist, 748f0bb7ee8SAdrian Hunter struct record_opts *opts, const char *str) 749f0bb7ee8SAdrian Hunter { 75035ac0cadSArnaldo Carvalho de Melo struct evsel_config_term *term; 751eb7a52d4SAdrian Hunter struct evsel *aux_evsel; 752eb7a52d4SAdrian Hunter bool has_aux_sample_size = false; 753f0bb7ee8SAdrian Hunter bool has_aux_leader = false; 754f0bb7ee8SAdrian Hunter struct evsel *evsel; 755f0bb7ee8SAdrian Hunter char *endptr; 756f0bb7ee8SAdrian Hunter unsigned long sz; 757f0bb7ee8SAdrian Hunter 758f0bb7ee8SAdrian Hunter if (!str) 759eb7a52d4SAdrian Hunter goto no_opt; 760f0bb7ee8SAdrian Hunter 761f0bb7ee8SAdrian Hunter if (!itr) { 762f0bb7ee8SAdrian Hunter pr_err("No AUX area event to sample\n"); 763f0bb7ee8SAdrian Hunter return -EINVAL; 764f0bb7ee8SAdrian Hunter } 765f0bb7ee8SAdrian Hunter 766f0bb7ee8SAdrian Hunter sz = strtoul(str, &endptr, 0); 767f0bb7ee8SAdrian Hunter if (*endptr || sz > UINT_MAX) { 768f0bb7ee8SAdrian Hunter pr_err("Bad AUX area sampling option: '%s'\n", str); 769f0bb7ee8SAdrian Hunter return -EINVAL; 770f0bb7ee8SAdrian Hunter } 771f0bb7ee8SAdrian Hunter 772f0bb7ee8SAdrian Hunter if (!sz) 773f0bb7ee8SAdrian Hunter sz = itr->default_aux_sample_size; 774f0bb7ee8SAdrian Hunter 775f0bb7ee8SAdrian Hunter if (!sz) 776f0bb7ee8SAdrian Hunter sz = DEFAULT_AUX_SAMPLE_SIZE; 777f0bb7ee8SAdrian Hunter 778f0bb7ee8SAdrian Hunter /* Set aux_sample_size based on --aux-sample option */ 779f0bb7ee8SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 780c754c382SArnaldo Carvalho de Melo if (evsel__is_group_leader(evsel)) { 78139453ed5SArnaldo Carvalho de Melo has_aux_leader = evsel__is_aux_event(evsel); 782f0bb7ee8SAdrian Hunter } else if (has_aux_leader) { 783f0bb7ee8SAdrian Hunter evsel->core.attr.aux_sample_size = sz; 784f0bb7ee8SAdrian Hunter } 785f0bb7ee8SAdrian Hunter } 786eb7a52d4SAdrian Hunter no_opt: 787eb7a52d4SAdrian Hunter aux_evsel = NULL; 788eb7a52d4SAdrian Hunter /* Override with aux_sample_size from config term */ 789eb7a52d4SAdrian Hunter evlist__for_each_entry(evlist, evsel) { 79039453ed5SArnaldo Carvalho de Melo if (evsel__is_aux_event(evsel)) 791eb7a52d4SAdrian Hunter aux_evsel = evsel; 79235ac0cadSArnaldo Carvalho de Melo term = evsel__get_config_term(evsel, AUX_SAMPLE_SIZE); 793eb7a52d4SAdrian Hunter if (term) { 794eb7a52d4SAdrian Hunter has_aux_sample_size = true; 795eb7a52d4SAdrian Hunter evsel->core.attr.aux_sample_size = term->val.aux_sample_size; 796eb7a52d4SAdrian Hunter /* If possible, group with the AUX event */ 797eb7a52d4SAdrian Hunter if (aux_evsel && evsel->core.attr.aux_sample_size) 79864b4778bSArnaldo Carvalho de Melo evlist__regroup(evlist, aux_evsel, evsel); 799eb7a52d4SAdrian Hunter } 800eb7a52d4SAdrian Hunter } 801eb7a52d4SAdrian Hunter 802eb7a52d4SAdrian Hunter if (!str && !has_aux_sample_size) 803eb7a52d4SAdrian Hunter return 0; 804eb7a52d4SAdrian Hunter 805eb7a52d4SAdrian Hunter if (!itr) { 806eb7a52d4SAdrian Hunter pr_err("No AUX area event to sample\n"); 807eb7a52d4SAdrian Hunter return -EINVAL; 808eb7a52d4SAdrian Hunter } 809f0bb7ee8SAdrian Hunter 810f0bb7ee8SAdrian Hunter return auxtrace_validate_aux_sample_size(evlist, opts); 811f0bb7ee8SAdrian Hunter } 812f0bb7ee8SAdrian Hunter 813d58b3f7eSAdrian Hunter void auxtrace_regroup_aux_output(struct evlist *evlist) 814d58b3f7eSAdrian Hunter { 815d58b3f7eSAdrian Hunter struct evsel *evsel, *aux_evsel = NULL; 816d58b3f7eSAdrian Hunter struct evsel_config_term *term; 817d58b3f7eSAdrian Hunter 818d58b3f7eSAdrian Hunter evlist__for_each_entry(evlist, evsel) { 819d58b3f7eSAdrian Hunter if (evsel__is_aux_event(evsel)) 820d58b3f7eSAdrian Hunter aux_evsel = evsel; 821d58b3f7eSAdrian Hunter term = evsel__get_config_term(evsel, AUX_OUTPUT); 822d58b3f7eSAdrian Hunter /* If possible, group with the AUX event */ 823d58b3f7eSAdrian Hunter if (term && aux_evsel) 824d58b3f7eSAdrian Hunter evlist__regroup(evlist, aux_evsel, evsel); 825d58b3f7eSAdrian Hunter } 826d58b3f7eSAdrian Hunter } 827d58b3f7eSAdrian Hunter 8289e0cc4feSAdrian Hunter struct auxtrace_record *__weak 82963503dbaSJiri Olsa auxtrace_record__init(struct evlist *evlist __maybe_unused, int *err) 8309e0cc4feSAdrian Hunter { 8319e0cc4feSAdrian Hunter *err = 0; 8329e0cc4feSAdrian Hunter return NULL; 8339e0cc4feSAdrian Hunter } 8349e0cc4feSAdrian Hunter 83599fa2984SAdrian Hunter static int auxtrace_index__alloc(struct list_head *head) 83699fa2984SAdrian Hunter { 83799fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 83899fa2984SAdrian Hunter 83999fa2984SAdrian Hunter auxtrace_index = malloc(sizeof(struct auxtrace_index)); 84099fa2984SAdrian Hunter if (!auxtrace_index) 84199fa2984SAdrian Hunter return -ENOMEM; 84299fa2984SAdrian Hunter 84399fa2984SAdrian Hunter auxtrace_index->nr = 0; 84499fa2984SAdrian Hunter INIT_LIST_HEAD(&auxtrace_index->list); 84599fa2984SAdrian Hunter 84699fa2984SAdrian Hunter list_add_tail(&auxtrace_index->list, head); 84799fa2984SAdrian Hunter 84899fa2984SAdrian Hunter return 0; 84999fa2984SAdrian Hunter } 85099fa2984SAdrian Hunter 85199fa2984SAdrian Hunter void auxtrace_index__free(struct list_head *head) 85299fa2984SAdrian Hunter { 85399fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index, *n; 85499fa2984SAdrian Hunter 85599fa2984SAdrian Hunter list_for_each_entry_safe(auxtrace_index, n, head, list) { 856e56fbc9dSArnaldo Carvalho de Melo list_del_init(&auxtrace_index->list); 85799fa2984SAdrian Hunter free(auxtrace_index); 85899fa2984SAdrian Hunter } 85999fa2984SAdrian Hunter } 86099fa2984SAdrian Hunter 86199fa2984SAdrian Hunter static struct auxtrace_index *auxtrace_index__last(struct list_head *head) 86299fa2984SAdrian Hunter { 86399fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 86499fa2984SAdrian Hunter int err; 86599fa2984SAdrian Hunter 86699fa2984SAdrian Hunter if (list_empty(head)) { 86799fa2984SAdrian Hunter err = auxtrace_index__alloc(head); 86899fa2984SAdrian Hunter if (err) 86999fa2984SAdrian Hunter return NULL; 87099fa2984SAdrian Hunter } 87199fa2984SAdrian Hunter 87299fa2984SAdrian Hunter auxtrace_index = list_entry(head->prev, struct auxtrace_index, list); 87399fa2984SAdrian Hunter 87499fa2984SAdrian Hunter if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) { 87599fa2984SAdrian Hunter err = auxtrace_index__alloc(head); 87699fa2984SAdrian Hunter if (err) 87799fa2984SAdrian Hunter return NULL; 87899fa2984SAdrian Hunter auxtrace_index = list_entry(head->prev, struct auxtrace_index, 87999fa2984SAdrian Hunter list); 88099fa2984SAdrian Hunter } 88199fa2984SAdrian Hunter 88299fa2984SAdrian Hunter return auxtrace_index; 88399fa2984SAdrian Hunter } 88499fa2984SAdrian Hunter 88599fa2984SAdrian Hunter int auxtrace_index__auxtrace_event(struct list_head *head, 88699fa2984SAdrian Hunter union perf_event *event, off_t file_offset) 88799fa2984SAdrian Hunter { 88899fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 88999fa2984SAdrian Hunter size_t nr; 89099fa2984SAdrian Hunter 89199fa2984SAdrian Hunter auxtrace_index = auxtrace_index__last(head); 89299fa2984SAdrian Hunter if (!auxtrace_index) 89399fa2984SAdrian Hunter return -ENOMEM; 89499fa2984SAdrian Hunter 89599fa2984SAdrian Hunter nr = auxtrace_index->nr; 89699fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = file_offset; 89799fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = event->header.size; 89899fa2984SAdrian Hunter auxtrace_index->nr += 1; 89999fa2984SAdrian Hunter 90099fa2984SAdrian Hunter return 0; 90199fa2984SAdrian Hunter } 90299fa2984SAdrian Hunter 90399fa2984SAdrian Hunter static int auxtrace_index__do_write(int fd, 90499fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index) 90599fa2984SAdrian Hunter { 90699fa2984SAdrian Hunter struct auxtrace_index_entry ent; 90799fa2984SAdrian Hunter size_t i; 90899fa2984SAdrian Hunter 90999fa2984SAdrian Hunter for (i = 0; i < auxtrace_index->nr; i++) { 91099fa2984SAdrian Hunter ent.file_offset = auxtrace_index->entries[i].file_offset; 91199fa2984SAdrian Hunter ent.sz = auxtrace_index->entries[i].sz; 91299fa2984SAdrian Hunter if (writen(fd, &ent, sizeof(ent)) != sizeof(ent)) 91399fa2984SAdrian Hunter return -errno; 91499fa2984SAdrian Hunter } 91599fa2984SAdrian Hunter return 0; 91699fa2984SAdrian Hunter } 91799fa2984SAdrian Hunter 91899fa2984SAdrian Hunter int auxtrace_index__write(int fd, struct list_head *head) 91999fa2984SAdrian Hunter { 92099fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 92199fa2984SAdrian Hunter u64 total = 0; 92299fa2984SAdrian Hunter int err; 92399fa2984SAdrian Hunter 92499fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, head, list) 92599fa2984SAdrian Hunter total += auxtrace_index->nr; 92699fa2984SAdrian Hunter 92799fa2984SAdrian Hunter if (writen(fd, &total, sizeof(total)) != sizeof(total)) 92899fa2984SAdrian Hunter return -errno; 92999fa2984SAdrian Hunter 93099fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, head, list) { 93199fa2984SAdrian Hunter err = auxtrace_index__do_write(fd, auxtrace_index); 93299fa2984SAdrian Hunter if (err) 93399fa2984SAdrian Hunter return err; 93499fa2984SAdrian Hunter } 93599fa2984SAdrian Hunter 93699fa2984SAdrian Hunter return 0; 93799fa2984SAdrian Hunter } 93899fa2984SAdrian Hunter 93999fa2984SAdrian Hunter static int auxtrace_index__process_entry(int fd, struct list_head *head, 94099fa2984SAdrian Hunter bool needs_swap) 94199fa2984SAdrian Hunter { 94299fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 94399fa2984SAdrian Hunter struct auxtrace_index_entry ent; 94499fa2984SAdrian Hunter size_t nr; 94599fa2984SAdrian Hunter 94699fa2984SAdrian Hunter if (readn(fd, &ent, sizeof(ent)) != sizeof(ent)) 94799fa2984SAdrian Hunter return -1; 94899fa2984SAdrian Hunter 94999fa2984SAdrian Hunter auxtrace_index = auxtrace_index__last(head); 95099fa2984SAdrian Hunter if (!auxtrace_index) 95199fa2984SAdrian Hunter return -1; 95299fa2984SAdrian Hunter 95399fa2984SAdrian Hunter nr = auxtrace_index->nr; 95499fa2984SAdrian Hunter if (needs_swap) { 95599fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = 95699fa2984SAdrian Hunter bswap_64(ent.file_offset); 95799fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = bswap_64(ent.sz); 95899fa2984SAdrian Hunter } else { 95999fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = ent.file_offset; 96099fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = ent.sz; 96199fa2984SAdrian Hunter } 96299fa2984SAdrian Hunter 96399fa2984SAdrian Hunter auxtrace_index->nr = nr + 1; 96499fa2984SAdrian Hunter 96599fa2984SAdrian Hunter return 0; 96699fa2984SAdrian Hunter } 96799fa2984SAdrian Hunter 96899fa2984SAdrian Hunter int auxtrace_index__process(int fd, u64 size, struct perf_session *session, 96999fa2984SAdrian Hunter bool needs_swap) 97099fa2984SAdrian Hunter { 97199fa2984SAdrian Hunter struct list_head *head = &session->auxtrace_index; 97299fa2984SAdrian Hunter u64 nr; 97399fa2984SAdrian Hunter 97499fa2984SAdrian Hunter if (readn(fd, &nr, sizeof(u64)) != sizeof(u64)) 97599fa2984SAdrian Hunter return -1; 97699fa2984SAdrian Hunter 97799fa2984SAdrian Hunter if (needs_swap) 97899fa2984SAdrian Hunter nr = bswap_64(nr); 97999fa2984SAdrian Hunter 98099fa2984SAdrian Hunter if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size) 98199fa2984SAdrian Hunter return -1; 98299fa2984SAdrian Hunter 98399fa2984SAdrian Hunter while (nr--) { 98499fa2984SAdrian Hunter int err; 98599fa2984SAdrian Hunter 98699fa2984SAdrian Hunter err = auxtrace_index__process_entry(fd, head, needs_swap); 98799fa2984SAdrian Hunter if (err) 98899fa2984SAdrian Hunter return -1; 98999fa2984SAdrian Hunter } 99099fa2984SAdrian Hunter 99199fa2984SAdrian Hunter return 0; 99299fa2984SAdrian Hunter } 99399fa2984SAdrian Hunter 99499fa2984SAdrian Hunter static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues, 99599fa2984SAdrian Hunter struct perf_session *session, 99699fa2984SAdrian Hunter struct auxtrace_index_entry *ent) 99799fa2984SAdrian Hunter { 99899fa2984SAdrian Hunter return auxtrace_queues__add_indexed_event(queues, session, 99999fa2984SAdrian Hunter ent->file_offset, ent->sz); 100099fa2984SAdrian Hunter } 100199fa2984SAdrian Hunter 100299fa2984SAdrian Hunter int auxtrace_queues__process_index(struct auxtrace_queues *queues, 100399fa2984SAdrian Hunter struct perf_session *session) 100499fa2984SAdrian Hunter { 100599fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 100699fa2984SAdrian Hunter struct auxtrace_index_entry *ent; 100799fa2984SAdrian Hunter size_t i; 100899fa2984SAdrian Hunter int err; 100999fa2984SAdrian Hunter 10102e2967f4SAdrian Hunter if (auxtrace__dont_decode(session)) 10112e2967f4SAdrian Hunter return 0; 10122e2967f4SAdrian Hunter 101399fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { 101499fa2984SAdrian Hunter for (i = 0; i < auxtrace_index->nr; i++) { 101599fa2984SAdrian Hunter ent = &auxtrace_index->entries[i]; 101699fa2984SAdrian Hunter err = auxtrace_queues__process_index_entry(queues, 101799fa2984SAdrian Hunter session, 101899fa2984SAdrian Hunter ent); 101999fa2984SAdrian Hunter if (err) 102099fa2984SAdrian Hunter return err; 102199fa2984SAdrian Hunter } 102299fa2984SAdrian Hunter } 102399fa2984SAdrian Hunter return 0; 102499fa2984SAdrian Hunter } 102599fa2984SAdrian Hunter 1026e5027893SAdrian Hunter struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, 1027e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 1028e5027893SAdrian Hunter { 1029e5027893SAdrian Hunter if (buffer) { 1030e5027893SAdrian Hunter if (list_is_last(&buffer->list, &queue->head)) 1031e5027893SAdrian Hunter return NULL; 1032e5027893SAdrian Hunter return list_entry(buffer->list.next, struct auxtrace_buffer, 1033e5027893SAdrian Hunter list); 1034e5027893SAdrian Hunter } else { 1035e5027893SAdrian Hunter if (list_empty(&queue->head)) 1036e5027893SAdrian Hunter return NULL; 1037e5027893SAdrian Hunter return list_entry(queue->head.next, struct auxtrace_buffer, 1038e5027893SAdrian Hunter list); 1039e5027893SAdrian Hunter } 1040e5027893SAdrian Hunter } 1041e5027893SAdrian Hunter 1042ac2f445fSAdrian Hunter struct auxtrace_queue *auxtrace_queues__sample_queue(struct auxtrace_queues *queues, 1043ac2f445fSAdrian Hunter struct perf_sample *sample, 1044ac2f445fSAdrian Hunter struct perf_session *session) 1045ac2f445fSAdrian Hunter { 1046ac2f445fSAdrian Hunter struct perf_sample_id *sid; 1047ac2f445fSAdrian Hunter unsigned int idx; 1048ac2f445fSAdrian Hunter u64 id; 1049ac2f445fSAdrian Hunter 1050ac2f445fSAdrian Hunter id = sample->id; 1051ac2f445fSAdrian Hunter if (!id) 1052ac2f445fSAdrian Hunter return NULL; 1053ac2f445fSAdrian Hunter 10543ccf8a7bSArnaldo Carvalho de Melo sid = evlist__id2sid(session->evlist, id); 1055ac2f445fSAdrian Hunter if (!sid) 1056ac2f445fSAdrian Hunter return NULL; 1057ac2f445fSAdrian Hunter 1058ac2f445fSAdrian Hunter idx = sid->idx; 1059ac2f445fSAdrian Hunter 1060ac2f445fSAdrian Hunter if (idx >= queues->nr_queues) 1061ac2f445fSAdrian Hunter return NULL; 1062ac2f445fSAdrian Hunter 1063ac2f445fSAdrian Hunter return &queues->queue_array[idx]; 1064ac2f445fSAdrian Hunter } 1065ac2f445fSAdrian Hunter 1066ac2f445fSAdrian Hunter int auxtrace_queues__add_sample(struct auxtrace_queues *queues, 1067ac2f445fSAdrian Hunter struct perf_session *session, 1068ac2f445fSAdrian Hunter struct perf_sample *sample, u64 data_offset, 1069ac2f445fSAdrian Hunter u64 reference) 1070ac2f445fSAdrian Hunter { 1071ac2f445fSAdrian Hunter struct auxtrace_buffer buffer = { 1072ac2f445fSAdrian Hunter .pid = -1, 1073ac2f445fSAdrian Hunter .data_offset = data_offset, 1074ac2f445fSAdrian Hunter .reference = reference, 1075ac2f445fSAdrian Hunter .size = sample->aux_sample.size, 1076ac2f445fSAdrian Hunter }; 1077ac2f445fSAdrian Hunter struct perf_sample_id *sid; 1078ac2f445fSAdrian Hunter u64 id = sample->id; 1079ac2f445fSAdrian Hunter unsigned int idx; 1080ac2f445fSAdrian Hunter 1081ac2f445fSAdrian Hunter if (!id) 1082ac2f445fSAdrian Hunter return -EINVAL; 1083ac2f445fSAdrian Hunter 10843ccf8a7bSArnaldo Carvalho de Melo sid = evlist__id2sid(session->evlist, id); 1085ac2f445fSAdrian Hunter if (!sid) 1086ac2f445fSAdrian Hunter return -ENOENT; 1087ac2f445fSAdrian Hunter 1088ac2f445fSAdrian Hunter idx = sid->idx; 1089ac2f445fSAdrian Hunter buffer.tid = sid->tid; 1090ac2f445fSAdrian Hunter buffer.cpu = sid->cpu; 1091ac2f445fSAdrian Hunter 1092ac2f445fSAdrian Hunter return auxtrace_queues__add_buffer(queues, session, idx, &buffer, NULL); 1093ac2f445fSAdrian Hunter } 1094ac2f445fSAdrian Hunter 1095ac2f445fSAdrian Hunter struct queue_data { 1096ac2f445fSAdrian Hunter bool samples; 1097ac2f445fSAdrian Hunter bool events; 1098ac2f445fSAdrian Hunter }; 1099ac2f445fSAdrian Hunter 1100ac2f445fSAdrian Hunter static int auxtrace_queue_data_cb(struct perf_session *session, 1101ac2f445fSAdrian Hunter union perf_event *event, u64 offset, 1102ac2f445fSAdrian Hunter void *data) 1103ac2f445fSAdrian Hunter { 1104ac2f445fSAdrian Hunter struct queue_data *qd = data; 1105ac2f445fSAdrian Hunter struct perf_sample sample; 1106ac2f445fSAdrian Hunter int err; 1107ac2f445fSAdrian Hunter 1108ac2f445fSAdrian Hunter if (qd->events && event->header.type == PERF_RECORD_AUXTRACE) { 1109ac2f445fSAdrian Hunter if (event->header.size < sizeof(struct perf_record_auxtrace)) 1110ac2f445fSAdrian Hunter return -EINVAL; 1111ac2f445fSAdrian Hunter offset += event->header.size; 1112ac2f445fSAdrian Hunter return session->auxtrace->queue_data(session, NULL, event, 1113ac2f445fSAdrian Hunter offset); 1114ac2f445fSAdrian Hunter } 1115ac2f445fSAdrian Hunter 1116ac2f445fSAdrian Hunter if (!qd->samples || event->header.type != PERF_RECORD_SAMPLE) 1117ac2f445fSAdrian Hunter return 0; 1118ac2f445fSAdrian Hunter 11192a6599cdSArnaldo Carvalho de Melo err = evlist__parse_sample(session->evlist, event, &sample); 1120ac2f445fSAdrian Hunter if (err) 1121ac2f445fSAdrian Hunter return err; 1122ac2f445fSAdrian Hunter 1123ac2f445fSAdrian Hunter if (!sample.aux_sample.size) 1124ac2f445fSAdrian Hunter return 0; 1125ac2f445fSAdrian Hunter 1126ac2f445fSAdrian Hunter offset += sample.aux_sample.data - (void *)event; 1127ac2f445fSAdrian Hunter 1128ac2f445fSAdrian Hunter return session->auxtrace->queue_data(session, &sample, NULL, offset); 1129ac2f445fSAdrian Hunter } 1130ac2f445fSAdrian Hunter 1131ac2f445fSAdrian Hunter int auxtrace_queue_data(struct perf_session *session, bool samples, bool events) 1132ac2f445fSAdrian Hunter { 1133ac2f445fSAdrian Hunter struct queue_data qd = { 1134ac2f445fSAdrian Hunter .samples = samples, 1135ac2f445fSAdrian Hunter .events = events, 1136ac2f445fSAdrian Hunter }; 1137ac2f445fSAdrian Hunter 1138ac2f445fSAdrian Hunter if (auxtrace__dont_decode(session)) 1139ac2f445fSAdrian Hunter return 0; 1140ac2f445fSAdrian Hunter 1141aeb802f8SNamhyung Kim if (perf_data__is_pipe(session->data)) 1142aeb802f8SNamhyung Kim return 0; 1143aeb802f8SNamhyung Kim 1144ac2f445fSAdrian Hunter if (!session->auxtrace || !session->auxtrace->queue_data) 1145ac2f445fSAdrian Hunter return -EINVAL; 1146ac2f445fSAdrian Hunter 1147ac2f445fSAdrian Hunter return perf_session__peek_events(session, session->header.data_offset, 1148ac2f445fSAdrian Hunter session->header.data_size, 1149ac2f445fSAdrian Hunter auxtrace_queue_data_cb, &qd); 1150ac2f445fSAdrian Hunter } 1151ac2f445fSAdrian Hunter 11526aa3afc9SAdrian Hunter void *auxtrace_buffer__get_data_rw(struct auxtrace_buffer *buffer, int fd, bool rw) 1153e5027893SAdrian Hunter { 11546aa3afc9SAdrian Hunter int prot = rw ? PROT_READ | PROT_WRITE : PROT_READ; 1155e5027893SAdrian Hunter size_t adj = buffer->data_offset & (page_size - 1); 1156e5027893SAdrian Hunter size_t size = buffer->size + adj; 1157e5027893SAdrian Hunter off_t file_offset = buffer->data_offset - adj; 1158e5027893SAdrian Hunter void *addr; 1159e5027893SAdrian Hunter 1160e5027893SAdrian Hunter if (buffer->data) 1161e5027893SAdrian Hunter return buffer->data; 1162e5027893SAdrian Hunter 11636aa3afc9SAdrian Hunter addr = mmap(NULL, size, prot, MAP_SHARED, fd, file_offset); 1164e5027893SAdrian Hunter if (addr == MAP_FAILED) 1165e5027893SAdrian Hunter return NULL; 1166e5027893SAdrian Hunter 1167e5027893SAdrian Hunter buffer->mmap_addr = addr; 1168e5027893SAdrian Hunter buffer->mmap_size = size; 1169e5027893SAdrian Hunter 1170e5027893SAdrian Hunter buffer->data = addr + adj; 1171e5027893SAdrian Hunter 1172e5027893SAdrian Hunter return buffer->data; 1173e5027893SAdrian Hunter } 1174e5027893SAdrian Hunter 1175e5027893SAdrian Hunter void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer) 1176e5027893SAdrian Hunter { 1177e5027893SAdrian Hunter if (!buffer->data || !buffer->mmap_addr) 1178e5027893SAdrian Hunter return; 1179e5027893SAdrian Hunter munmap(buffer->mmap_addr, buffer->mmap_size); 1180e5027893SAdrian Hunter buffer->mmap_addr = NULL; 1181e5027893SAdrian Hunter buffer->mmap_size = 0; 1182e5027893SAdrian Hunter buffer->data = NULL; 1183e5027893SAdrian Hunter buffer->use_data = NULL; 1184e5027893SAdrian Hunter } 1185e5027893SAdrian Hunter 1186e5027893SAdrian Hunter void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer) 1187e5027893SAdrian Hunter { 1188e5027893SAdrian Hunter auxtrace_buffer__put_data(buffer); 1189e5027893SAdrian Hunter if (buffer->data_needs_freeing) { 1190e5027893SAdrian Hunter buffer->data_needs_freeing = false; 1191e5027893SAdrian Hunter zfree(&buffer->data); 1192e5027893SAdrian Hunter buffer->use_data = NULL; 1193e5027893SAdrian Hunter buffer->size = 0; 1194e5027893SAdrian Hunter } 1195e5027893SAdrian Hunter } 1196e5027893SAdrian Hunter 1197e5027893SAdrian Hunter void auxtrace_buffer__free(struct auxtrace_buffer *buffer) 1198e5027893SAdrian Hunter { 1199e5027893SAdrian Hunter auxtrace_buffer__drop_data(buffer); 1200e5027893SAdrian Hunter free(buffer); 1201e5027893SAdrian Hunter } 1202e5027893SAdrian Hunter 12037151c1d1SAdrian Hunter void auxtrace_synth_guest_error(struct perf_record_auxtrace_error *auxtrace_error, int type, 120485ed4729SAdrian Hunter int code, int cpu, pid_t pid, pid_t tid, u64 ip, 12057151c1d1SAdrian Hunter const char *msg, u64 timestamp, 12067151c1d1SAdrian Hunter pid_t machine_pid, int vcpu) 120785ed4729SAdrian Hunter { 120885ed4729SAdrian Hunter size_t size; 120985ed4729SAdrian Hunter 121072932371SJiri Olsa memset(auxtrace_error, 0, sizeof(struct perf_record_auxtrace_error)); 121185ed4729SAdrian Hunter 121285ed4729SAdrian Hunter auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; 121385ed4729SAdrian Hunter auxtrace_error->type = type; 121485ed4729SAdrian Hunter auxtrace_error->code = code; 121585ed4729SAdrian Hunter auxtrace_error->cpu = cpu; 121685ed4729SAdrian Hunter auxtrace_error->pid = pid; 121785ed4729SAdrian Hunter auxtrace_error->tid = tid; 121816bd4321SAdrian Hunter auxtrace_error->fmt = 1; 121985ed4729SAdrian Hunter auxtrace_error->ip = ip; 122016bd4321SAdrian Hunter auxtrace_error->time = timestamp; 122185ed4729SAdrian Hunter strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG); 12227151c1d1SAdrian Hunter if (machine_pid) { 12237151c1d1SAdrian Hunter auxtrace_error->fmt = 2; 12247151c1d1SAdrian Hunter auxtrace_error->machine_pid = machine_pid; 12257151c1d1SAdrian Hunter auxtrace_error->vcpu = vcpu; 12267151c1d1SAdrian Hunter size = sizeof(*auxtrace_error); 12277151c1d1SAdrian Hunter } else { 122885ed4729SAdrian Hunter size = (void *)auxtrace_error->msg - (void *)auxtrace_error + 122985ed4729SAdrian Hunter strlen(auxtrace_error->msg) + 1; 12307151c1d1SAdrian Hunter } 123185ed4729SAdrian Hunter auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64)); 123285ed4729SAdrian Hunter } 123385ed4729SAdrian Hunter 12347151c1d1SAdrian Hunter void auxtrace_synth_error(struct perf_record_auxtrace_error *auxtrace_error, int type, 12357151c1d1SAdrian Hunter int code, int cpu, pid_t pid, pid_t tid, u64 ip, 12367151c1d1SAdrian Hunter const char *msg, u64 timestamp) 12377151c1d1SAdrian Hunter { 12387151c1d1SAdrian Hunter auxtrace_synth_guest_error(auxtrace_error, type, code, cpu, pid, tid, 12397151c1d1SAdrian Hunter ip, msg, timestamp, 0, -1); 12407151c1d1SAdrian Hunter } 12417151c1d1SAdrian Hunter 12429e0cc4feSAdrian Hunter int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, 12439e0cc4feSAdrian Hunter struct perf_tool *tool, 12449e0cc4feSAdrian Hunter struct perf_session *session, 12459e0cc4feSAdrian Hunter perf_event__handler_t process) 12469e0cc4feSAdrian Hunter { 12479e0cc4feSAdrian Hunter union perf_event *ev; 12489e0cc4feSAdrian Hunter size_t priv_size; 12499e0cc4feSAdrian Hunter int err; 12509e0cc4feSAdrian Hunter 12519e0cc4feSAdrian Hunter pr_debug2("Synthesizing auxtrace information\n"); 125214a05e13SMathieu Poirier priv_size = auxtrace_record__info_priv_size(itr, session->evlist); 125372932371SJiri Olsa ev = zalloc(sizeof(struct perf_record_auxtrace_info) + priv_size); 12549e0cc4feSAdrian Hunter if (!ev) 12559e0cc4feSAdrian Hunter return -ENOMEM; 12569e0cc4feSAdrian Hunter 12579e0cc4feSAdrian Hunter ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO; 125872932371SJiri Olsa ev->auxtrace_info.header.size = sizeof(struct perf_record_auxtrace_info) + 12599e0cc4feSAdrian Hunter priv_size; 12609e0cc4feSAdrian Hunter err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info, 12619e0cc4feSAdrian Hunter priv_size); 12629e0cc4feSAdrian Hunter if (err) 12639e0cc4feSAdrian Hunter goto out_free; 12649e0cc4feSAdrian Hunter 12659e0cc4feSAdrian Hunter err = process(tool, ev, NULL, NULL); 12669e0cc4feSAdrian Hunter out_free: 12679e0cc4feSAdrian Hunter free(ev); 12689e0cc4feSAdrian Hunter return err; 12699e0cc4feSAdrian Hunter } 12709e0cc4feSAdrian Hunter 12715c7bec0cSAdrian Hunter static void unleader_evsel(struct evlist *evlist, struct evsel *leader) 12725c7bec0cSAdrian Hunter { 12735c7bec0cSAdrian Hunter struct evsel *new_leader = NULL; 12745c7bec0cSAdrian Hunter struct evsel *evsel; 12755c7bec0cSAdrian Hunter 12765c7bec0cSAdrian Hunter /* Find new leader for the group */ 12775c7bec0cSAdrian Hunter evlist__for_each_entry(evlist, evsel) { 1278fba7c866SJiri Olsa if (!evsel__has_leader(evsel, leader) || evsel == leader) 12795c7bec0cSAdrian Hunter continue; 12805c7bec0cSAdrian Hunter if (!new_leader) 12815c7bec0cSAdrian Hunter new_leader = evsel; 1282fba7c866SJiri Olsa evsel__set_leader(evsel, new_leader); 12835c7bec0cSAdrian Hunter } 12845c7bec0cSAdrian Hunter 12855c7bec0cSAdrian Hunter /* Update group information */ 12865c7bec0cSAdrian Hunter if (new_leader) { 12875c7bec0cSAdrian Hunter zfree(&new_leader->group_name); 12885c7bec0cSAdrian Hunter new_leader->group_name = leader->group_name; 12895c7bec0cSAdrian Hunter leader->group_name = NULL; 12905c7bec0cSAdrian Hunter 12915c7bec0cSAdrian Hunter new_leader->core.nr_members = leader->core.nr_members - 1; 12925c7bec0cSAdrian Hunter leader->core.nr_members = 1; 12935c7bec0cSAdrian Hunter } 12945c7bec0cSAdrian Hunter } 12955c7bec0cSAdrian Hunter 12965c7bec0cSAdrian Hunter static void unleader_auxtrace(struct perf_session *session) 12975c7bec0cSAdrian Hunter { 12985c7bec0cSAdrian Hunter struct evsel *evsel; 12995c7bec0cSAdrian Hunter 13005c7bec0cSAdrian Hunter evlist__for_each_entry(session->evlist, evsel) { 13015c7bec0cSAdrian Hunter if (auxtrace__evsel_is_auxtrace(session, evsel) && 1302c754c382SArnaldo Carvalho de Melo evsel__is_group_leader(evsel)) { 13035c7bec0cSAdrian Hunter unleader_evsel(session->evlist, evsel); 13045c7bec0cSAdrian Hunter } 13055c7bec0cSAdrian Hunter } 13065c7bec0cSAdrian Hunter } 13075c7bec0cSAdrian Hunter 130889f1688aSJiri Olsa int perf_event__process_auxtrace_info(struct perf_session *session, 130989f1688aSJiri Olsa union perf_event *event) 131073f75fb1SAdrian Hunter { 131173f75fb1SAdrian Hunter enum auxtrace_type type = event->auxtrace_info.type; 13125c7bec0cSAdrian Hunter int err; 131373f75fb1SAdrian Hunter 131473f75fb1SAdrian Hunter if (dump_trace) 131573f75fb1SAdrian Hunter fprintf(stdout, " type: %u\n", type); 131673f75fb1SAdrian Hunter 131773f75fb1SAdrian Hunter switch (type) { 131855ea4ab4SAdrian Hunter case PERF_AUXTRACE_INTEL_PT: 13195c7bec0cSAdrian Hunter err = intel_pt_process_auxtrace_info(event, session); 13205c7bec0cSAdrian Hunter break; 1321d0170af7SAdrian Hunter case PERF_AUXTRACE_INTEL_BTS: 13225c7bec0cSAdrian Hunter err = intel_bts_process_auxtrace_info(event, session); 13235c7bec0cSAdrian Hunter break; 1324ffd3d18cSKim Phillips case PERF_AUXTRACE_ARM_SPE: 13255c7bec0cSAdrian Hunter err = arm_spe_process_auxtrace_info(event, session); 13265c7bec0cSAdrian Hunter break; 1327a818c563SMathieu Poirier case PERF_AUXTRACE_CS_ETM: 13285c7bec0cSAdrian Hunter err = cs_etm__process_auxtrace_info(event, session); 13295c7bec0cSAdrian Hunter break; 1330b96e6615SThomas Richter case PERF_AUXTRACE_S390_CPUMSF: 13315c7bec0cSAdrian Hunter err = s390_cpumsf_process_auxtrace_info(event, session); 13325c7bec0cSAdrian Hunter break; 1333057381a7SQi Liu case PERF_AUXTRACE_HISI_PTT: 13345e91e57eSQi Liu err = hisi_ptt_process_auxtrace_info(event, session); 13355e91e57eSQi Liu break; 133673f75fb1SAdrian Hunter case PERF_AUXTRACE_UNKNOWN: 133773f75fb1SAdrian Hunter default: 133873f75fb1SAdrian Hunter return -EINVAL; 133973f75fb1SAdrian Hunter } 13405c7bec0cSAdrian Hunter 13415c7bec0cSAdrian Hunter if (err) 13425c7bec0cSAdrian Hunter return err; 13435c7bec0cSAdrian Hunter 13445c7bec0cSAdrian Hunter unleader_auxtrace(session); 13455c7bec0cSAdrian Hunter 13465c7bec0cSAdrian Hunter return 0; 134773f75fb1SAdrian Hunter } 134873f75fb1SAdrian Hunter 13497336555aSJiri Olsa s64 perf_event__process_auxtrace(struct perf_session *session, 13507336555aSJiri Olsa union perf_event *event) 135173f75fb1SAdrian Hunter { 135273f75fb1SAdrian Hunter s64 err; 135373f75fb1SAdrian Hunter 135473f75fb1SAdrian Hunter if (dump_trace) 1355306c9d24SJiri Olsa fprintf(stdout, " size: %#"PRI_lx64" offset: %#"PRI_lx64" ref: %#"PRI_lx64" idx: %u tid: %d cpu: %d\n", 135673f75fb1SAdrian Hunter event->auxtrace.size, event->auxtrace.offset, 135773f75fb1SAdrian Hunter event->auxtrace.reference, event->auxtrace.idx, 135873f75fb1SAdrian Hunter event->auxtrace.tid, event->auxtrace.cpu); 135973f75fb1SAdrian Hunter 136073f75fb1SAdrian Hunter if (auxtrace__dont_decode(session)) 136173f75fb1SAdrian Hunter return event->auxtrace.size; 136273f75fb1SAdrian Hunter 136373f75fb1SAdrian Hunter if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE) 136473f75fb1SAdrian Hunter return -EINVAL; 136573f75fb1SAdrian Hunter 13667336555aSJiri Olsa err = session->auxtrace->process_auxtrace_event(session, event, session->tool); 136773f75fb1SAdrian Hunter if (err < 0) 136873f75fb1SAdrian Hunter return err; 136973f75fb1SAdrian Hunter 137073f75fb1SAdrian Hunter return event->auxtrace.size; 137173f75fb1SAdrian Hunter } 137273f75fb1SAdrian Hunter 1373f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS 1374f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD 100000 1375f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 1376f6986c95SAdrian Hunter #define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 1377601897b5SAdrian Hunter #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 1378601897b5SAdrian Hunter #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 1379f6986c95SAdrian Hunter 13804eb06815SAndi Kleen void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, 13814eb06815SAndi Kleen bool no_sample) 1382f6986c95SAdrian Hunter { 1383f6986c95SAdrian Hunter synth_opts->branches = true; 138453c76b0eSAdrian Hunter synth_opts->transactions = true; 13853bdafdffSAdrian Hunter synth_opts->ptwrites = true; 138670d110d7SAdrian Hunter synth_opts->pwr_events = true; 1387181ebb5eSAdrian Hunter synth_opts->other_events = true; 13888ee9a9abSAdrian Hunter synth_opts->intr_events = true; 1389f6986c95SAdrian Hunter synth_opts->errors = true; 13909f74d770STan Xiaojun synth_opts->flc = true; 13919f74d770STan Xiaojun synth_opts->llc = true; 13929f74d770STan Xiaojun synth_opts->tlb = true; 1393014a771cSLeo Yan synth_opts->mem = true; 13949f74d770STan Xiaojun synth_opts->remote_access = true; 13959f74d770STan Xiaojun 13964eb06815SAndi Kleen if (no_sample) { 13974eb06815SAndi Kleen synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; 13984eb06815SAndi Kleen synth_opts->period = 1; 13994eb06815SAndi Kleen synth_opts->calls = true; 14004eb06815SAndi Kleen } else { 14014eb06815SAndi Kleen synth_opts->instructions = true; 14027e55b956SSteinar H. Gunderson synth_opts->cycles = true; 1403f6986c95SAdrian Hunter synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; 1404f6986c95SAdrian Hunter synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 14054eb06815SAndi Kleen } 1406f6986c95SAdrian Hunter synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 1407601897b5SAdrian Hunter synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 1408d1706b39SAndi Kleen synth_opts->initial_skip = 0; 1409f6986c95SAdrian Hunter } 1410f6986c95SAdrian Hunter 1411cb971438SAdrian Hunter static int get_flag(const char **ptr, unsigned int *flags) 1412cb971438SAdrian Hunter { 1413cb971438SAdrian Hunter while (1) { 1414cb971438SAdrian Hunter char c = **ptr; 1415cb971438SAdrian Hunter 1416cb971438SAdrian Hunter if (c >= 'a' && c <= 'z') { 1417cb971438SAdrian Hunter *flags |= 1 << (c - 'a'); 1418cb971438SAdrian Hunter ++*ptr; 1419cb971438SAdrian Hunter return 0; 1420cb971438SAdrian Hunter } else if (c == ' ') { 1421cb971438SAdrian Hunter ++*ptr; 1422cb971438SAdrian Hunter continue; 1423cb971438SAdrian Hunter } else { 1424cb971438SAdrian Hunter return -1; 1425cb971438SAdrian Hunter } 1426cb971438SAdrian Hunter } 1427cb971438SAdrian Hunter } 1428cb971438SAdrian Hunter 1429cb971438SAdrian Hunter static int get_flags(const char **ptr, unsigned int *plus_flags, unsigned int *minus_flags) 1430cb971438SAdrian Hunter { 1431cb971438SAdrian Hunter while (1) { 1432cb971438SAdrian Hunter switch (**ptr) { 1433cb971438SAdrian Hunter case '+': 1434cb971438SAdrian Hunter ++*ptr; 1435cb971438SAdrian Hunter if (get_flag(ptr, plus_flags)) 1436cb971438SAdrian Hunter return -1; 1437cb971438SAdrian Hunter break; 1438cb971438SAdrian Hunter case '-': 1439cb971438SAdrian Hunter ++*ptr; 1440cb971438SAdrian Hunter if (get_flag(ptr, minus_flags)) 1441cb971438SAdrian Hunter return -1; 1442cb971438SAdrian Hunter break; 1443cb971438SAdrian Hunter case ' ': 1444cb971438SAdrian Hunter ++*ptr; 1445cb971438SAdrian Hunter break; 1446cb971438SAdrian Hunter default: 1447cb971438SAdrian Hunter return 0; 1448cb971438SAdrian Hunter } 1449cb971438SAdrian Hunter } 1450cb971438SAdrian Hunter } 1451cb971438SAdrian Hunter 1452a7fdd30aSAdrian Hunter #define ITRACE_DFLT_LOG_ON_ERROR_SZ 16384 1453a7fdd30aSAdrian Hunter 1454a7fdd30aSAdrian Hunter static unsigned int itrace_log_on_error_size(void) 1455a7fdd30aSAdrian Hunter { 1456a7fdd30aSAdrian Hunter unsigned int sz = 0; 1457a7fdd30aSAdrian Hunter 1458a7fdd30aSAdrian Hunter perf_config_scan("itrace.debug-log-buffer-size", "%u", &sz); 1459a7fdd30aSAdrian Hunter return sz ?: ITRACE_DFLT_LOG_ON_ERROR_SZ; 1460a7fdd30aSAdrian Hunter } 1461a7fdd30aSAdrian Hunter 1462f6986c95SAdrian Hunter /* 1463f6986c95SAdrian Hunter * Please check tools/perf/Documentation/perf-script.txt for information 1464f6986c95SAdrian Hunter * about the options parsed here, which is introduced after this cset, 1465f6986c95SAdrian Hunter * when support in 'perf script' for these options is introduced. 1466f6986c95SAdrian Hunter */ 1467e621b8ffSAdrian Hunter int itrace_do_parse_synth_opts(struct itrace_synth_opts *synth_opts, 1468e621b8ffSAdrian Hunter const char *str, int unset) 1469f6986c95SAdrian Hunter { 1470f6986c95SAdrian Hunter const char *p; 1471f6986c95SAdrian Hunter char *endptr; 1472f70cfa07SAdrian Hunter bool period_type_set = false; 1473e1791347SAdrian Hunter bool period_set = false; 1474bb69c912SAdrian Hunter bool iy = false; 1475f6986c95SAdrian Hunter 1476f6986c95SAdrian Hunter synth_opts->set = true; 1477f6986c95SAdrian Hunter 1478f6986c95SAdrian Hunter if (unset) { 1479f6986c95SAdrian Hunter synth_opts->dont_decode = true; 1480f6986c95SAdrian Hunter return 0; 1481f6986c95SAdrian Hunter } 1482f6986c95SAdrian Hunter 1483f6986c95SAdrian Hunter if (!str) { 1484355200e0SAdrian Hunter itrace_synth_opts__set_default(synth_opts, 1485355200e0SAdrian Hunter synth_opts->default_no_sample); 1486f6986c95SAdrian Hunter return 0; 1487f6986c95SAdrian Hunter } 1488f6986c95SAdrian Hunter 1489f6986c95SAdrian Hunter for (p = str; *p;) { 1490f6986c95SAdrian Hunter switch (*p++) { 1491f6986c95SAdrian Hunter case 'i': 14927e55b956SSteinar H. Gunderson case 'y': 1493bb69c912SAdrian Hunter iy = true; 14947e55b956SSteinar H. Gunderson if (p[-1] == 'y') 14957e55b956SSteinar H. Gunderson synth_opts->cycles = true; 14967e55b956SSteinar H. Gunderson else 1497f6986c95SAdrian Hunter synth_opts->instructions = true; 1498f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1499f6986c95SAdrian Hunter p += 1; 1500f6986c95SAdrian Hunter if (isdigit(*p)) { 1501f6986c95SAdrian Hunter synth_opts->period = strtoull(p, &endptr, 10); 1502e1791347SAdrian Hunter period_set = true; 1503f6986c95SAdrian Hunter p = endptr; 1504f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1505f6986c95SAdrian Hunter p += 1; 1506f6986c95SAdrian Hunter switch (*p++) { 1507f6986c95SAdrian Hunter case 'i': 1508f6986c95SAdrian Hunter synth_opts->period_type = 1509f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_INSTRUCTIONS; 1510f70cfa07SAdrian Hunter period_type_set = true; 1511f6986c95SAdrian Hunter break; 1512f6986c95SAdrian Hunter case 't': 1513f6986c95SAdrian Hunter synth_opts->period_type = 1514f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_TICKS; 1515f70cfa07SAdrian Hunter period_type_set = true; 1516f6986c95SAdrian Hunter break; 1517f6986c95SAdrian Hunter case 'm': 1518f6986c95SAdrian Hunter synth_opts->period *= 1000; 1519f6986c95SAdrian Hunter /* Fall through */ 1520f6986c95SAdrian Hunter case 'u': 1521f6986c95SAdrian Hunter synth_opts->period *= 1000; 1522f6986c95SAdrian Hunter /* Fall through */ 1523f6986c95SAdrian Hunter case 'n': 1524f6986c95SAdrian Hunter if (*p++ != 's') 1525f6986c95SAdrian Hunter goto out_err; 1526f6986c95SAdrian Hunter synth_opts->period_type = 1527f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_NANOSECS; 1528f70cfa07SAdrian Hunter period_type_set = true; 1529f6986c95SAdrian Hunter break; 1530f6986c95SAdrian Hunter case '\0': 1531f6986c95SAdrian Hunter goto out; 1532f6986c95SAdrian Hunter default: 1533f6986c95SAdrian Hunter goto out_err; 1534f6986c95SAdrian Hunter } 1535f6986c95SAdrian Hunter } 1536f6986c95SAdrian Hunter break; 1537f6986c95SAdrian Hunter case 'b': 1538f6986c95SAdrian Hunter synth_opts->branches = true; 1539f6986c95SAdrian Hunter break; 154053c76b0eSAdrian Hunter case 'x': 154153c76b0eSAdrian Hunter synth_opts->transactions = true; 154253c76b0eSAdrian Hunter break; 15433bdafdffSAdrian Hunter case 'w': 15443bdafdffSAdrian Hunter synth_opts->ptwrites = true; 15453bdafdffSAdrian Hunter break; 154670d110d7SAdrian Hunter case 'p': 154770d110d7SAdrian Hunter synth_opts->pwr_events = true; 154870d110d7SAdrian Hunter break; 1549181ebb5eSAdrian Hunter case 'o': 1550181ebb5eSAdrian Hunter synth_opts->other_events = true; 1551181ebb5eSAdrian Hunter break; 15528ee9a9abSAdrian Hunter case 'I': 15538ee9a9abSAdrian Hunter synth_opts->intr_events = true; 15548ee9a9abSAdrian Hunter break; 1555f6986c95SAdrian Hunter case 'e': 1556f6986c95SAdrian Hunter synth_opts->errors = true; 1557cb971438SAdrian Hunter if (get_flags(&p, &synth_opts->error_plus_flags, 1558cb971438SAdrian Hunter &synth_opts->error_minus_flags)) 1559cb971438SAdrian Hunter goto out_err; 1560f6986c95SAdrian Hunter break; 1561f6986c95SAdrian Hunter case 'd': 1562f6986c95SAdrian Hunter synth_opts->log = true; 1563935aac2dSAdrian Hunter if (get_flags(&p, &synth_opts->log_plus_flags, 1564935aac2dSAdrian Hunter &synth_opts->log_minus_flags)) 1565935aac2dSAdrian Hunter goto out_err; 1566a7fdd30aSAdrian Hunter if (synth_opts->log_plus_flags & AUXTRACE_LOG_FLG_ON_ERROR) 1567a7fdd30aSAdrian Hunter synth_opts->log_on_error_size = itrace_log_on_error_size(); 1568f6986c95SAdrian Hunter break; 1569f6986c95SAdrian Hunter case 'c': 1570f6986c95SAdrian Hunter synth_opts->branches = true; 1571f6986c95SAdrian Hunter synth_opts->calls = true; 1572f6986c95SAdrian Hunter break; 1573f6986c95SAdrian Hunter case 'r': 1574f6986c95SAdrian Hunter synth_opts->branches = true; 1575f6986c95SAdrian Hunter synth_opts->returns = true; 1576f6986c95SAdrian Hunter break; 15771c5c25b3SAdrian Hunter case 'G': 1578f6986c95SAdrian Hunter case 'g': 15791c5c25b3SAdrian Hunter if (p[-1] == 'G') 15801c5c25b3SAdrian Hunter synth_opts->add_callchain = true; 15811c5c25b3SAdrian Hunter else 1582f6986c95SAdrian Hunter synth_opts->callchain = true; 1583f6986c95SAdrian Hunter synth_opts->callchain_sz = 1584f6986c95SAdrian Hunter PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 1585f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1586f6986c95SAdrian Hunter p += 1; 1587f6986c95SAdrian Hunter if (isdigit(*p)) { 1588f6986c95SAdrian Hunter unsigned int val; 1589f6986c95SAdrian Hunter 1590f6986c95SAdrian Hunter val = strtoul(p, &endptr, 10); 1591f6986c95SAdrian Hunter p = endptr; 1592f6986c95SAdrian Hunter if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ) 1593f6986c95SAdrian Hunter goto out_err; 1594f6986c95SAdrian Hunter synth_opts->callchain_sz = val; 1595f6986c95SAdrian Hunter } 1596f6986c95SAdrian Hunter break; 1597ec90e42cSAdrian Hunter case 'L': 1598601897b5SAdrian Hunter case 'l': 1599ec90e42cSAdrian Hunter if (p[-1] == 'L') 1600ec90e42cSAdrian Hunter synth_opts->add_last_branch = true; 1601ec90e42cSAdrian Hunter else 1602601897b5SAdrian Hunter synth_opts->last_branch = true; 1603601897b5SAdrian Hunter synth_opts->last_branch_sz = 1604601897b5SAdrian Hunter PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 1605601897b5SAdrian Hunter while (*p == ' ' || *p == ',') 1606601897b5SAdrian Hunter p += 1; 1607601897b5SAdrian Hunter if (isdigit(*p)) { 1608601897b5SAdrian Hunter unsigned int val; 1609601897b5SAdrian Hunter 1610601897b5SAdrian Hunter val = strtoul(p, &endptr, 10); 1611601897b5SAdrian Hunter p = endptr; 1612601897b5SAdrian Hunter if (!val || 1613601897b5SAdrian Hunter val > PERF_ITRACE_MAX_LAST_BRANCH_SZ) 1614601897b5SAdrian Hunter goto out_err; 1615601897b5SAdrian Hunter synth_opts->last_branch_sz = val; 1616601897b5SAdrian Hunter } 1617601897b5SAdrian Hunter break; 1618d1706b39SAndi Kleen case 's': 1619d1706b39SAndi Kleen synth_opts->initial_skip = strtoul(p, &endptr, 10); 1620d1706b39SAndi Kleen if (p == endptr) 1621d1706b39SAndi Kleen goto out_err; 1622d1706b39SAndi Kleen p = endptr; 1623d1706b39SAndi Kleen break; 16249f74d770STan Xiaojun case 'f': 16259f74d770STan Xiaojun synth_opts->flc = true; 16269f74d770STan Xiaojun break; 16279f74d770STan Xiaojun case 'm': 16289f74d770STan Xiaojun synth_opts->llc = true; 16299f74d770STan Xiaojun break; 16309f74d770STan Xiaojun case 't': 16319f74d770STan Xiaojun synth_opts->tlb = true; 16329f74d770STan Xiaojun break; 16339f74d770STan Xiaojun case 'a': 16349f74d770STan Xiaojun synth_opts->remote_access = true; 16359f74d770STan Xiaojun break; 1636014a771cSLeo Yan case 'M': 1637014a771cSLeo Yan synth_opts->mem = true; 1638014a771cSLeo Yan break; 163951971536SAdrian Hunter case 'q': 164051971536SAdrian Hunter synth_opts->quick += 1; 164151971536SAdrian Hunter break; 1642b6778fe1SAdrian Hunter case 'A': 1643b6778fe1SAdrian Hunter synth_opts->approx_ipc = true; 1644b6778fe1SAdrian Hunter break; 164518f49494SAdrian Hunter case 'Z': 164618f49494SAdrian Hunter synth_opts->timeless_decoding = true; 164718f49494SAdrian Hunter break; 164826218331SLeo Yan case 'T': 164926218331SLeo Yan synth_opts->use_timestamp = true; 165026218331SLeo Yan break; 1651f6986c95SAdrian Hunter case ' ': 1652f6986c95SAdrian Hunter case ',': 1653f6986c95SAdrian Hunter break; 1654f6986c95SAdrian Hunter default: 1655f6986c95SAdrian Hunter goto out_err; 1656f6986c95SAdrian Hunter } 1657f6986c95SAdrian Hunter } 1658f6986c95SAdrian Hunter out: 1659bb69c912SAdrian Hunter if (iy) { 1660f70cfa07SAdrian Hunter if (!period_type_set) 1661f6986c95SAdrian Hunter synth_opts->period_type = 1662f6986c95SAdrian Hunter PERF_ITRACE_DEFAULT_PERIOD_TYPE; 1663e1791347SAdrian Hunter if (!period_set) 1664f6986c95SAdrian Hunter synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 1665f6986c95SAdrian Hunter } 1666f6986c95SAdrian Hunter 1667f6986c95SAdrian Hunter return 0; 1668f6986c95SAdrian Hunter 1669f6986c95SAdrian Hunter out_err: 1670f6986c95SAdrian Hunter pr_err("Bad Instruction Tracing options '%s'\n", str); 1671f6986c95SAdrian Hunter return -EINVAL; 1672f6986c95SAdrian Hunter } 1673f6986c95SAdrian Hunter 1674e621b8ffSAdrian Hunter int itrace_parse_synth_opts(const struct option *opt, const char *str, int unset) 1675e621b8ffSAdrian Hunter { 1676e621b8ffSAdrian Hunter return itrace_do_parse_synth_opts(opt->value, str, unset); 1677e621b8ffSAdrian Hunter } 1678e621b8ffSAdrian Hunter 167985ed4729SAdrian Hunter static const char * const auxtrace_error_type_name[] = { 168085ed4729SAdrian Hunter [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace", 168185ed4729SAdrian Hunter }; 168285ed4729SAdrian Hunter 168385ed4729SAdrian Hunter static const char *auxtrace_error_name(int type) 168485ed4729SAdrian Hunter { 168585ed4729SAdrian Hunter const char *error_type_name = NULL; 168685ed4729SAdrian Hunter 168785ed4729SAdrian Hunter if (type < PERF_AUXTRACE_ERROR_MAX) 168885ed4729SAdrian Hunter error_type_name = auxtrace_error_type_name[type]; 168985ed4729SAdrian Hunter if (!error_type_name) 169085ed4729SAdrian Hunter error_type_name = "unknown AUX"; 169185ed4729SAdrian Hunter return error_type_name; 169285ed4729SAdrian Hunter } 169385ed4729SAdrian Hunter 169485ed4729SAdrian Hunter size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) 169585ed4729SAdrian Hunter { 169672932371SJiri Olsa struct perf_record_auxtrace_error *e = &event->auxtrace_error; 169716bd4321SAdrian Hunter unsigned long long nsecs = e->time; 169816bd4321SAdrian Hunter const char *msg = e->msg; 169985ed4729SAdrian Hunter int ret; 170085ed4729SAdrian Hunter 170185ed4729SAdrian Hunter ret = fprintf(fp, " %s error type %u", 170285ed4729SAdrian Hunter auxtrace_error_name(e->type), e->type); 170316bd4321SAdrian Hunter 170416bd4321SAdrian Hunter if (e->fmt && nsecs) { 170516bd4321SAdrian Hunter unsigned long secs = nsecs / NSEC_PER_SEC; 170616bd4321SAdrian Hunter 170716bd4321SAdrian Hunter nsecs -= secs * NSEC_PER_SEC; 170816bd4321SAdrian Hunter ret += fprintf(fp, " time %lu.%09llu", secs, nsecs); 170916bd4321SAdrian Hunter } else { 171016bd4321SAdrian Hunter ret += fprintf(fp, " time 0"); 171116bd4321SAdrian Hunter } 171216bd4321SAdrian Hunter 171316bd4321SAdrian Hunter if (!e->fmt) 171416bd4321SAdrian Hunter msg = (const char *)&e->time; 171516bd4321SAdrian Hunter 17167151c1d1SAdrian Hunter if (e->fmt >= 2 && e->machine_pid) 17177151c1d1SAdrian Hunter ret += fprintf(fp, " machine_pid %d vcpu %d", e->machine_pid, e->vcpu); 17187151c1d1SAdrian Hunter 17193460efb2SJiri Olsa ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRI_lx64" code %u: %s\n", 172016bd4321SAdrian Hunter e->cpu, e->pid, e->tid, e->ip, e->code, msg); 172185ed4729SAdrian Hunter return ret; 172285ed4729SAdrian Hunter } 172385ed4729SAdrian Hunter 172485ed4729SAdrian Hunter void perf_session__auxtrace_error_inc(struct perf_session *session, 172585ed4729SAdrian Hunter union perf_event *event) 172685ed4729SAdrian Hunter { 172772932371SJiri Olsa struct perf_record_auxtrace_error *e = &event->auxtrace_error; 172885ed4729SAdrian Hunter 172985ed4729SAdrian Hunter if (e->type < PERF_AUXTRACE_ERROR_MAX) 173085ed4729SAdrian Hunter session->evlist->stats.nr_auxtrace_errors[e->type] += 1; 173185ed4729SAdrian Hunter } 173285ed4729SAdrian Hunter 173385ed4729SAdrian Hunter void events_stats__auxtrace_error_warn(const struct events_stats *stats) 173485ed4729SAdrian Hunter { 173585ed4729SAdrian Hunter int i; 173685ed4729SAdrian Hunter 173785ed4729SAdrian Hunter for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) { 173885ed4729SAdrian Hunter if (!stats->nr_auxtrace_errors[i]) 173985ed4729SAdrian Hunter continue; 174085ed4729SAdrian Hunter ui__warning("%u %s errors\n", 174185ed4729SAdrian Hunter stats->nr_auxtrace_errors[i], 174285ed4729SAdrian Hunter auxtrace_error_name(i)); 174385ed4729SAdrian Hunter } 174485ed4729SAdrian Hunter } 174585ed4729SAdrian Hunter 174689f1688aSJiri Olsa int perf_event__process_auxtrace_error(struct perf_session *session, 174789f1688aSJiri Olsa union perf_event *event) 174885ed4729SAdrian Hunter { 174973f75fb1SAdrian Hunter if (auxtrace__dont_decode(session)) 175073f75fb1SAdrian Hunter return 0; 175173f75fb1SAdrian Hunter 175285ed4729SAdrian Hunter perf_event__fprintf_auxtrace_error(event, stdout); 175385ed4729SAdrian Hunter return 0; 175485ed4729SAdrian Hunter } 175585ed4729SAdrian Hunter 1756bbc49f12SLeo Yan /* 1757bbc49f12SLeo Yan * In the compat mode kernel runs in 64-bit and perf tool runs in 32-bit mode, 1758bbc49f12SLeo Yan * 32-bit perf tool cannot access 64-bit value atomically, which might lead to 1759bbc49f12SLeo Yan * the issues caused by the below sequence on multiple CPUs: when perf tool 1760bbc49f12SLeo Yan * accesses either the load operation or the store operation for 64-bit value, 1761bbc49f12SLeo Yan * on some architectures the operation is divided into two instructions, one 1762bbc49f12SLeo Yan * is for accessing the low 32-bit value and another is for the high 32-bit; 1763bbc49f12SLeo Yan * thus these two user operations can give the kernel chances to access the 1764bbc49f12SLeo Yan * 64-bit value, and thus leads to the unexpected load values. 1765bbc49f12SLeo Yan * 1766bbc49f12SLeo Yan * kernel (64-bit) user (32-bit) 1767bbc49f12SLeo Yan * 1768bbc49f12SLeo Yan * if (LOAD ->aux_tail) { --, LOAD ->aux_head_lo 1769bbc49f12SLeo Yan * STORE $aux_data | ,---> 1770bbc49f12SLeo Yan * FLUSH $aux_data | | LOAD ->aux_head_hi 1771bbc49f12SLeo Yan * STORE ->aux_head --|-------` smp_rmb() 1772bbc49f12SLeo Yan * } | LOAD $data 1773bbc49f12SLeo Yan * | smp_mb() 1774bbc49f12SLeo Yan * | STORE ->aux_tail_lo 1775bbc49f12SLeo Yan * `-----------> 1776bbc49f12SLeo Yan * STORE ->aux_tail_hi 1777bbc49f12SLeo Yan * 1778bbc49f12SLeo Yan * For this reason, it's impossible for the perf tool to work correctly when 1779bbc49f12SLeo Yan * the AUX head or tail is bigger than 4GB (more than 32 bits length); and we 1780bbc49f12SLeo Yan * can not simply limit the AUX ring buffer to less than 4GB, the reason is 1781bbc49f12SLeo Yan * the pointers can be increased monotonically, whatever the buffer size it is, 1782bbc49f12SLeo Yan * at the end the head and tail can be bigger than 4GB and carry out to the 1783bbc49f12SLeo Yan * high 32-bit. 1784bbc49f12SLeo Yan * 1785bbc49f12SLeo Yan * To mitigate the issues and improve the user experience, we can allow the 1786bbc49f12SLeo Yan * perf tool working in certain conditions and bail out with error if detect 1787bbc49f12SLeo Yan * any overflow cannot be handled. 1788bbc49f12SLeo Yan * 1789bbc49f12SLeo Yan * For reading the AUX head, it reads out the values for three times, and 1790bbc49f12SLeo Yan * compares the high 4 bytes of the values between the first time and the last 1791bbc49f12SLeo Yan * time, if there has no change for high 4 bytes injected by the kernel during 1792bbc49f12SLeo Yan * the user reading sequence, it's safe for use the second value. 1793bbc49f12SLeo Yan * 1794bbc49f12SLeo Yan * When compat_auxtrace_mmap__write_tail() detects any carrying in the high 1795bbc49f12SLeo Yan * 32 bits, it means there have two store operations in user space and it cannot 1796bbc49f12SLeo Yan * promise the atomicity for 64-bit write, so return '-1' in this case to tell 1797bbc49f12SLeo Yan * the caller an overflow error has happened. 1798bbc49f12SLeo Yan */ 1799bbc49f12SLeo Yan u64 __weak compat_auxtrace_mmap__read_head(struct auxtrace_mmap *mm) 1800bbc49f12SLeo Yan { 1801bbc49f12SLeo Yan struct perf_event_mmap_page *pc = mm->userpg; 1802bbc49f12SLeo Yan u64 first, second, last; 1803bbc49f12SLeo Yan u64 mask = (u64)(UINT32_MAX) << 32; 1804bbc49f12SLeo Yan 1805bbc49f12SLeo Yan do { 1806bbc49f12SLeo Yan first = READ_ONCE(pc->aux_head); 1807bbc49f12SLeo Yan /* Ensure all reads are done after we read the head */ 1808bbc49f12SLeo Yan smp_rmb(); 1809bbc49f12SLeo Yan second = READ_ONCE(pc->aux_head); 1810bbc49f12SLeo Yan /* Ensure all reads are done after we read the head */ 1811bbc49f12SLeo Yan smp_rmb(); 1812bbc49f12SLeo Yan last = READ_ONCE(pc->aux_head); 1813bbc49f12SLeo Yan } while ((first & mask) != (last & mask)); 1814bbc49f12SLeo Yan 1815bbc49f12SLeo Yan return second; 1816bbc49f12SLeo Yan } 1817bbc49f12SLeo Yan 1818bbc49f12SLeo Yan int __weak compat_auxtrace_mmap__write_tail(struct auxtrace_mmap *mm, u64 tail) 1819bbc49f12SLeo Yan { 1820bbc49f12SLeo Yan struct perf_event_mmap_page *pc = mm->userpg; 1821bbc49f12SLeo Yan u64 mask = (u64)(UINT32_MAX) << 32; 1822bbc49f12SLeo Yan 1823bbc49f12SLeo Yan if (tail & mask) 1824bbc49f12SLeo Yan return -1; 1825bbc49f12SLeo Yan 1826bbc49f12SLeo Yan /* Ensure all reads are done before we write the tail out */ 1827bbc49f12SLeo Yan smp_mb(); 1828bbc49f12SLeo Yan WRITE_ONCE(pc->aux_tail, tail); 1829bbc49f12SLeo Yan return 0; 1830bbc49f12SLeo Yan } 1831bbc49f12SLeo Yan 1832a5830532SJiri Olsa static int __auxtrace_mmap__read(struct mmap *map, 1833d20031bbSAdrian Hunter struct auxtrace_record *itr, 1834d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn, 1835d20031bbSAdrian Hunter bool snapshot, size_t snapshot_size) 18369e0cc4feSAdrian Hunter { 1837e035f4caSJiri Olsa struct auxtrace_mmap *mm = &map->auxtrace_mmap; 1838d20031bbSAdrian Hunter u64 head, old = mm->prev, offset, ref; 18399e0cc4feSAdrian Hunter unsigned char *data = mm->base; 18409e0cc4feSAdrian Hunter size_t size, head_off, old_off, len1, len2, padding; 18419e0cc4feSAdrian Hunter union perf_event ev; 18429e0cc4feSAdrian Hunter void *data1, *data2; 1843bbc49f12SLeo Yan int kernel_is_64_bit = perf_env__kernel_is_64_bit(evsel__env(NULL)); 18449e0cc4feSAdrian Hunter 1845bbc49f12SLeo Yan head = auxtrace_mmap__read_head(mm, kernel_is_64_bit); 18469d645033SLeo Yan 18479d645033SLeo Yan if (snapshot && 18489d645033SLeo Yan auxtrace_record__find_snapshot(itr, mm->idx, mm, data, &head, &old)) 18499d645033SLeo Yan return -1; 1850d20031bbSAdrian Hunter 18519e0cc4feSAdrian Hunter if (old == head) 18529e0cc4feSAdrian Hunter return 0; 18539e0cc4feSAdrian Hunter 18549e0cc4feSAdrian Hunter pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n", 18559e0cc4feSAdrian Hunter mm->idx, old, head, head - old); 18569e0cc4feSAdrian Hunter 18579e0cc4feSAdrian Hunter if (mm->mask) { 18589e0cc4feSAdrian Hunter head_off = head & mm->mask; 18599e0cc4feSAdrian Hunter old_off = old & mm->mask; 18609e0cc4feSAdrian Hunter } else { 18619e0cc4feSAdrian Hunter head_off = head % mm->len; 18629e0cc4feSAdrian Hunter old_off = old % mm->len; 18639e0cc4feSAdrian Hunter } 18649e0cc4feSAdrian Hunter 18659e0cc4feSAdrian Hunter if (head_off > old_off) 18669e0cc4feSAdrian Hunter size = head_off - old_off; 18679e0cc4feSAdrian Hunter else 18689e0cc4feSAdrian Hunter size = mm->len - (old_off - head_off); 18699e0cc4feSAdrian Hunter 1870d20031bbSAdrian Hunter if (snapshot && size > snapshot_size) 1871d20031bbSAdrian Hunter size = snapshot_size; 1872d20031bbSAdrian Hunter 18739e0cc4feSAdrian Hunter ref = auxtrace_record__reference(itr); 18749e0cc4feSAdrian Hunter 18759e0cc4feSAdrian Hunter if (head > old || size <= head || mm->mask) { 18769e0cc4feSAdrian Hunter offset = head - size; 18779e0cc4feSAdrian Hunter } else { 18789e0cc4feSAdrian Hunter /* 18799e0cc4feSAdrian Hunter * When the buffer size is not a power of 2, 'head' wraps at the 18809e0cc4feSAdrian Hunter * highest multiple of the buffer size, so we have to subtract 18819e0cc4feSAdrian Hunter * the remainder here. 18829e0cc4feSAdrian Hunter */ 18839e0cc4feSAdrian Hunter u64 rem = (0ULL - mm->len) % mm->len; 18849e0cc4feSAdrian Hunter 18859e0cc4feSAdrian Hunter offset = head - size - rem; 18869e0cc4feSAdrian Hunter } 18879e0cc4feSAdrian Hunter 18889e0cc4feSAdrian Hunter if (size > head_off) { 18899e0cc4feSAdrian Hunter len1 = size - head_off; 18909e0cc4feSAdrian Hunter data1 = &data[mm->len - len1]; 18919e0cc4feSAdrian Hunter len2 = head_off; 18929e0cc4feSAdrian Hunter data2 = &data[0]; 18939e0cc4feSAdrian Hunter } else { 18949e0cc4feSAdrian Hunter len1 = size; 18959e0cc4feSAdrian Hunter data1 = &data[head_off - len1]; 18969e0cc4feSAdrian Hunter len2 = 0; 18979e0cc4feSAdrian Hunter data2 = NULL; 18989e0cc4feSAdrian Hunter } 18999e0cc4feSAdrian Hunter 190083b2ea25SAdrian Hunter if (itr->alignment) { 190183b2ea25SAdrian Hunter unsigned int unwanted = len1 % itr->alignment; 190283b2ea25SAdrian Hunter 190383b2ea25SAdrian Hunter len1 -= unwanted; 190483b2ea25SAdrian Hunter size -= unwanted; 190583b2ea25SAdrian Hunter } 190683b2ea25SAdrian Hunter 19079e0cc4feSAdrian Hunter /* padding must be written by fn() e.g. record__process_auxtrace() */ 1908c3fcadf0SAdrian Hunter padding = size & (PERF_AUXTRACE_RECORD_ALIGNMENT - 1); 19099e0cc4feSAdrian Hunter if (padding) 1910c3fcadf0SAdrian Hunter padding = PERF_AUXTRACE_RECORD_ALIGNMENT - padding; 19119e0cc4feSAdrian Hunter 19129e0cc4feSAdrian Hunter memset(&ev, 0, sizeof(ev)); 19139e0cc4feSAdrian Hunter ev.auxtrace.header.type = PERF_RECORD_AUXTRACE; 19149e0cc4feSAdrian Hunter ev.auxtrace.header.size = sizeof(ev.auxtrace); 19159e0cc4feSAdrian Hunter ev.auxtrace.size = size + padding; 19169e0cc4feSAdrian Hunter ev.auxtrace.offset = offset; 19179e0cc4feSAdrian Hunter ev.auxtrace.reference = ref; 19189e0cc4feSAdrian Hunter ev.auxtrace.idx = mm->idx; 19199e0cc4feSAdrian Hunter ev.auxtrace.tid = mm->tid; 19209e0cc4feSAdrian Hunter ev.auxtrace.cpu = mm->cpu; 19219e0cc4feSAdrian Hunter 1922ded2b8feSJiri Olsa if (fn(tool, map, &ev, data1, len1, data2, len2)) 19239e0cc4feSAdrian Hunter return -1; 19249e0cc4feSAdrian Hunter 19259e0cc4feSAdrian Hunter mm->prev = head; 19269e0cc4feSAdrian Hunter 1927d20031bbSAdrian Hunter if (!snapshot) { 19289e0cc4feSAdrian Hunter int err; 19299e0cc4feSAdrian Hunter 1930bbc49f12SLeo Yan err = auxtrace_mmap__write_tail(mm, head, kernel_is_64_bit); 1931bbc49f12SLeo Yan if (err < 0) 1932bbc49f12SLeo Yan return err; 1933bbc49f12SLeo Yan 1934bbc49f12SLeo Yan if (itr->read_finish) { 19359e0cc4feSAdrian Hunter err = itr->read_finish(itr, mm->idx); 19369e0cc4feSAdrian Hunter if (err < 0) 19379e0cc4feSAdrian Hunter return err; 19389e0cc4feSAdrian Hunter } 1939d20031bbSAdrian Hunter } 19409e0cc4feSAdrian Hunter 19419e0cc4feSAdrian Hunter return 1; 19429e0cc4feSAdrian Hunter } 1943c3278f02SAdrian Hunter 1944a5830532SJiri Olsa int auxtrace_mmap__read(struct mmap *map, struct auxtrace_record *itr, 1945d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn) 1946d20031bbSAdrian Hunter { 1947e035f4caSJiri Olsa return __auxtrace_mmap__read(map, itr, tool, fn, false, 0); 1948d20031bbSAdrian Hunter } 1949d20031bbSAdrian Hunter 1950a5830532SJiri Olsa int auxtrace_mmap__read_snapshot(struct mmap *map, 1951d20031bbSAdrian Hunter struct auxtrace_record *itr, 1952d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn, 1953d20031bbSAdrian Hunter size_t snapshot_size) 1954d20031bbSAdrian Hunter { 1955e035f4caSJiri Olsa return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size); 1956d20031bbSAdrian Hunter } 1957d20031bbSAdrian Hunter 1958c3278f02SAdrian Hunter /** 1959c3278f02SAdrian Hunter * struct auxtrace_cache - hash table to implement a cache 1960c3278f02SAdrian Hunter * @hashtable: the hashtable 1961c3278f02SAdrian Hunter * @sz: hashtable size (number of hlists) 1962c3278f02SAdrian Hunter * @entry_size: size of an entry 1963c3278f02SAdrian Hunter * @limit: limit the number of entries to this maximum, when reached the cache 1964c3278f02SAdrian Hunter * is dropped and caching begins again with an empty cache 1965c3278f02SAdrian Hunter * @cnt: current number of entries 1966c3278f02SAdrian Hunter * @bits: hashtable size (@sz = 2^@bits) 1967c3278f02SAdrian Hunter */ 1968c3278f02SAdrian Hunter struct auxtrace_cache { 1969c3278f02SAdrian Hunter struct hlist_head *hashtable; 1970c3278f02SAdrian Hunter size_t sz; 1971c3278f02SAdrian Hunter size_t entry_size; 1972c3278f02SAdrian Hunter size_t limit; 1973c3278f02SAdrian Hunter size_t cnt; 1974c3278f02SAdrian Hunter unsigned int bits; 1975c3278f02SAdrian Hunter }; 1976c3278f02SAdrian Hunter 1977c3278f02SAdrian Hunter struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size, 1978c3278f02SAdrian Hunter unsigned int limit_percent) 1979c3278f02SAdrian Hunter { 1980c3278f02SAdrian Hunter struct auxtrace_cache *c; 1981c3278f02SAdrian Hunter struct hlist_head *ht; 1982c3278f02SAdrian Hunter size_t sz, i; 1983c3278f02SAdrian Hunter 1984c3278f02SAdrian Hunter c = zalloc(sizeof(struct auxtrace_cache)); 1985c3278f02SAdrian Hunter if (!c) 1986c3278f02SAdrian Hunter return NULL; 1987c3278f02SAdrian Hunter 1988c3278f02SAdrian Hunter sz = 1UL << bits; 1989c3278f02SAdrian Hunter 1990c3278f02SAdrian Hunter ht = calloc(sz, sizeof(struct hlist_head)); 1991c3278f02SAdrian Hunter if (!ht) 1992c3278f02SAdrian Hunter goto out_free; 1993c3278f02SAdrian Hunter 1994c3278f02SAdrian Hunter for (i = 0; i < sz; i++) 1995c3278f02SAdrian Hunter INIT_HLIST_HEAD(&ht[i]); 1996c3278f02SAdrian Hunter 1997c3278f02SAdrian Hunter c->hashtable = ht; 1998c3278f02SAdrian Hunter c->sz = sz; 1999c3278f02SAdrian Hunter c->entry_size = entry_size; 2000c3278f02SAdrian Hunter c->limit = (c->sz * limit_percent) / 100; 2001c3278f02SAdrian Hunter c->bits = bits; 2002c3278f02SAdrian Hunter 2003c3278f02SAdrian Hunter return c; 2004c3278f02SAdrian Hunter 2005c3278f02SAdrian Hunter out_free: 2006c3278f02SAdrian Hunter free(c); 2007c3278f02SAdrian Hunter return NULL; 2008c3278f02SAdrian Hunter } 2009c3278f02SAdrian Hunter 2010c3278f02SAdrian Hunter static void auxtrace_cache__drop(struct auxtrace_cache *c) 2011c3278f02SAdrian Hunter { 2012c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry; 2013c3278f02SAdrian Hunter struct hlist_node *tmp; 2014c3278f02SAdrian Hunter size_t i; 2015c3278f02SAdrian Hunter 2016c3278f02SAdrian Hunter if (!c) 2017c3278f02SAdrian Hunter return; 2018c3278f02SAdrian Hunter 2019c3278f02SAdrian Hunter for (i = 0; i < c->sz; i++) { 2020c3278f02SAdrian Hunter hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) { 2021c3278f02SAdrian Hunter hlist_del(&entry->hash); 2022c3278f02SAdrian Hunter auxtrace_cache__free_entry(c, entry); 2023c3278f02SAdrian Hunter } 2024c3278f02SAdrian Hunter } 2025c3278f02SAdrian Hunter 2026c3278f02SAdrian Hunter c->cnt = 0; 2027c3278f02SAdrian Hunter } 2028c3278f02SAdrian Hunter 2029c3278f02SAdrian Hunter void auxtrace_cache__free(struct auxtrace_cache *c) 2030c3278f02SAdrian Hunter { 2031c3278f02SAdrian Hunter if (!c) 2032c3278f02SAdrian Hunter return; 2033c3278f02SAdrian Hunter 2034c3278f02SAdrian Hunter auxtrace_cache__drop(c); 2035d8f9da24SArnaldo Carvalho de Melo zfree(&c->hashtable); 2036c3278f02SAdrian Hunter free(c); 2037c3278f02SAdrian Hunter } 2038c3278f02SAdrian Hunter 2039c3278f02SAdrian Hunter void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c) 2040c3278f02SAdrian Hunter { 2041c3278f02SAdrian Hunter return malloc(c->entry_size); 2042c3278f02SAdrian Hunter } 2043c3278f02SAdrian Hunter 2044c3278f02SAdrian Hunter void auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused, 2045c3278f02SAdrian Hunter void *entry) 2046c3278f02SAdrian Hunter { 2047c3278f02SAdrian Hunter free(entry); 2048c3278f02SAdrian Hunter } 2049c3278f02SAdrian Hunter 2050c3278f02SAdrian Hunter int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, 2051c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry) 2052c3278f02SAdrian Hunter { 2053c3278f02SAdrian Hunter if (c->limit && ++c->cnt > c->limit) 2054c3278f02SAdrian Hunter auxtrace_cache__drop(c); 2055c3278f02SAdrian Hunter 2056c3278f02SAdrian Hunter entry->key = key; 2057c3278f02SAdrian Hunter hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]); 2058c3278f02SAdrian Hunter 2059c3278f02SAdrian Hunter return 0; 2060c3278f02SAdrian Hunter } 2061c3278f02SAdrian Hunter 2062fd62c109SAdrian Hunter static struct auxtrace_cache_entry *auxtrace_cache__rm(struct auxtrace_cache *c, 2063fd62c109SAdrian Hunter u32 key) 2064fd62c109SAdrian Hunter { 2065fd62c109SAdrian Hunter struct auxtrace_cache_entry *entry; 2066fd62c109SAdrian Hunter struct hlist_head *hlist; 2067fd62c109SAdrian Hunter struct hlist_node *n; 2068fd62c109SAdrian Hunter 2069fd62c109SAdrian Hunter if (!c) 2070fd62c109SAdrian Hunter return NULL; 2071fd62c109SAdrian Hunter 2072fd62c109SAdrian Hunter hlist = &c->hashtable[hash_32(key, c->bits)]; 2073fd62c109SAdrian Hunter hlist_for_each_entry_safe(entry, n, hlist, hash) { 2074fd62c109SAdrian Hunter if (entry->key == key) { 2075fd62c109SAdrian Hunter hlist_del(&entry->hash); 2076fd62c109SAdrian Hunter return entry; 2077fd62c109SAdrian Hunter } 2078fd62c109SAdrian Hunter } 2079fd62c109SAdrian Hunter 2080fd62c109SAdrian Hunter return NULL; 2081fd62c109SAdrian Hunter } 2082fd62c109SAdrian Hunter 2083fd62c109SAdrian Hunter void auxtrace_cache__remove(struct auxtrace_cache *c, u32 key) 2084fd62c109SAdrian Hunter { 2085fd62c109SAdrian Hunter struct auxtrace_cache_entry *entry = auxtrace_cache__rm(c, key); 2086fd62c109SAdrian Hunter 2087fd62c109SAdrian Hunter auxtrace_cache__free_entry(c, entry); 2088fd62c109SAdrian Hunter } 2089fd62c109SAdrian Hunter 2090c3278f02SAdrian Hunter void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key) 2091c3278f02SAdrian Hunter { 2092c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry; 2093c3278f02SAdrian Hunter struct hlist_head *hlist; 2094c3278f02SAdrian Hunter 2095c3278f02SAdrian Hunter if (!c) 2096c3278f02SAdrian Hunter return NULL; 2097c3278f02SAdrian Hunter 2098c3278f02SAdrian Hunter hlist = &c->hashtable[hash_32(key, c->bits)]; 2099c3278f02SAdrian Hunter hlist_for_each_entry(entry, hlist, hash) { 2100c3278f02SAdrian Hunter if (entry->key == key) 2101c3278f02SAdrian Hunter return entry; 2102c3278f02SAdrian Hunter } 2103c3278f02SAdrian Hunter 2104c3278f02SAdrian Hunter return NULL; 2105c3278f02SAdrian Hunter } 21061b36c03eSAdrian Hunter 21071b36c03eSAdrian Hunter static void addr_filter__free_str(struct addr_filter *filt) 21081b36c03eSAdrian Hunter { 2109d8f9da24SArnaldo Carvalho de Melo zfree(&filt->str); 21101b36c03eSAdrian Hunter filt->action = NULL; 21111b36c03eSAdrian Hunter filt->sym_from = NULL; 21121b36c03eSAdrian Hunter filt->sym_to = NULL; 21131b36c03eSAdrian Hunter filt->filename = NULL; 21141b36c03eSAdrian Hunter } 21151b36c03eSAdrian Hunter 21161b36c03eSAdrian Hunter static struct addr_filter *addr_filter__new(void) 21171b36c03eSAdrian Hunter { 21181b36c03eSAdrian Hunter struct addr_filter *filt = zalloc(sizeof(*filt)); 21191b36c03eSAdrian Hunter 21201b36c03eSAdrian Hunter if (filt) 21211b36c03eSAdrian Hunter INIT_LIST_HEAD(&filt->list); 21221b36c03eSAdrian Hunter 21231b36c03eSAdrian Hunter return filt; 21241b36c03eSAdrian Hunter } 21251b36c03eSAdrian Hunter 21261b36c03eSAdrian Hunter static void addr_filter__free(struct addr_filter *filt) 21271b36c03eSAdrian Hunter { 21281b36c03eSAdrian Hunter if (filt) 21291b36c03eSAdrian Hunter addr_filter__free_str(filt); 21301b36c03eSAdrian Hunter free(filt); 21311b36c03eSAdrian Hunter } 21321b36c03eSAdrian Hunter 21331b36c03eSAdrian Hunter static void addr_filters__add(struct addr_filters *filts, 21341b36c03eSAdrian Hunter struct addr_filter *filt) 21351b36c03eSAdrian Hunter { 21361b36c03eSAdrian Hunter list_add_tail(&filt->list, &filts->head); 21371b36c03eSAdrian Hunter filts->cnt += 1; 21381b36c03eSAdrian Hunter } 21391b36c03eSAdrian Hunter 21401b36c03eSAdrian Hunter static void addr_filters__del(struct addr_filters *filts, 21411b36c03eSAdrian Hunter struct addr_filter *filt) 21421b36c03eSAdrian Hunter { 21431b36c03eSAdrian Hunter list_del_init(&filt->list); 21441b36c03eSAdrian Hunter filts->cnt -= 1; 21451b36c03eSAdrian Hunter } 21461b36c03eSAdrian Hunter 21471b36c03eSAdrian Hunter void addr_filters__init(struct addr_filters *filts) 21481b36c03eSAdrian Hunter { 21491b36c03eSAdrian Hunter INIT_LIST_HEAD(&filts->head); 21501b36c03eSAdrian Hunter filts->cnt = 0; 21511b36c03eSAdrian Hunter } 21521b36c03eSAdrian Hunter 21531b36c03eSAdrian Hunter void addr_filters__exit(struct addr_filters *filts) 21541b36c03eSAdrian Hunter { 21551b36c03eSAdrian Hunter struct addr_filter *filt, *n; 21561b36c03eSAdrian Hunter 21571b36c03eSAdrian Hunter list_for_each_entry_safe(filt, n, &filts->head, list) { 21581b36c03eSAdrian Hunter addr_filters__del(filts, filt); 21591b36c03eSAdrian Hunter addr_filter__free(filt); 21601b36c03eSAdrian Hunter } 21611b36c03eSAdrian Hunter } 21621b36c03eSAdrian Hunter 21631b36c03eSAdrian Hunter static int parse_num_or_str(char **inp, u64 *num, const char **str, 21641b36c03eSAdrian Hunter const char *str_delim) 21651b36c03eSAdrian Hunter { 21661b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 21671b36c03eSAdrian Hunter 21681b36c03eSAdrian Hunter if (isdigit(**inp)) { 21691b36c03eSAdrian Hunter char *endptr; 21701b36c03eSAdrian Hunter 21711b36c03eSAdrian Hunter if (!num) 21721b36c03eSAdrian Hunter return -EINVAL; 21731b36c03eSAdrian Hunter errno = 0; 21741b36c03eSAdrian Hunter *num = strtoull(*inp, &endptr, 0); 21751b36c03eSAdrian Hunter if (errno) 21761b36c03eSAdrian Hunter return -errno; 21771b36c03eSAdrian Hunter if (endptr == *inp) 21781b36c03eSAdrian Hunter return -EINVAL; 21791b36c03eSAdrian Hunter *inp = endptr; 21801b36c03eSAdrian Hunter } else { 21811b36c03eSAdrian Hunter size_t n; 21821b36c03eSAdrian Hunter 21831b36c03eSAdrian Hunter if (!str) 21841b36c03eSAdrian Hunter return -EINVAL; 21851b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 21861b36c03eSAdrian Hunter *str = *inp; 21871b36c03eSAdrian Hunter n = strcspn(*inp, str_delim); 21881b36c03eSAdrian Hunter if (!n) 21891b36c03eSAdrian Hunter return -EINVAL; 21901b36c03eSAdrian Hunter *inp += n; 21911b36c03eSAdrian Hunter if (**inp) { 21921b36c03eSAdrian Hunter **inp = '\0'; 21931b36c03eSAdrian Hunter *inp += 1; 21941b36c03eSAdrian Hunter } 21951b36c03eSAdrian Hunter } 21961b36c03eSAdrian Hunter return 0; 21971b36c03eSAdrian Hunter } 21981b36c03eSAdrian Hunter 21991b36c03eSAdrian Hunter static int parse_action(struct addr_filter *filt) 22001b36c03eSAdrian Hunter { 22011b36c03eSAdrian Hunter if (!strcmp(filt->action, "filter")) { 22021b36c03eSAdrian Hunter filt->start = true; 22031b36c03eSAdrian Hunter filt->range = true; 22041b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "start")) { 22051b36c03eSAdrian Hunter filt->start = true; 22061b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "stop")) { 22071b36c03eSAdrian Hunter filt->start = false; 22081b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "tracestop")) { 22091b36c03eSAdrian Hunter filt->start = false; 22101b36c03eSAdrian Hunter filt->range = true; 22111b36c03eSAdrian Hunter filt->action += 5; /* Change 'tracestop' to 'stop' */ 22121b36c03eSAdrian Hunter } else { 22131b36c03eSAdrian Hunter return -EINVAL; 22141b36c03eSAdrian Hunter } 22151b36c03eSAdrian Hunter return 0; 22161b36c03eSAdrian Hunter } 22171b36c03eSAdrian Hunter 22181b36c03eSAdrian Hunter static int parse_sym_idx(char **inp, int *idx) 22191b36c03eSAdrian Hunter { 22201b36c03eSAdrian Hunter *idx = -1; 22211b36c03eSAdrian Hunter 22221b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 22231b36c03eSAdrian Hunter 22241b36c03eSAdrian Hunter if (**inp != '#') 22251b36c03eSAdrian Hunter return 0; 22261b36c03eSAdrian Hunter 22271b36c03eSAdrian Hunter *inp += 1; 22281b36c03eSAdrian Hunter 22291b36c03eSAdrian Hunter if (**inp == 'g' || **inp == 'G') { 22301b36c03eSAdrian Hunter *inp += 1; 22311b36c03eSAdrian Hunter *idx = 0; 22321b36c03eSAdrian Hunter } else { 22331b36c03eSAdrian Hunter unsigned long num; 22341b36c03eSAdrian Hunter char *endptr; 22351b36c03eSAdrian Hunter 22361b36c03eSAdrian Hunter errno = 0; 22371b36c03eSAdrian Hunter num = strtoul(*inp, &endptr, 0); 22381b36c03eSAdrian Hunter if (errno) 22391b36c03eSAdrian Hunter return -errno; 22401b36c03eSAdrian Hunter if (endptr == *inp || num > INT_MAX) 22411b36c03eSAdrian Hunter return -EINVAL; 22421b36c03eSAdrian Hunter *inp = endptr; 22431b36c03eSAdrian Hunter *idx = num; 22441b36c03eSAdrian Hunter } 22451b36c03eSAdrian Hunter 22461b36c03eSAdrian Hunter return 0; 22471b36c03eSAdrian Hunter } 22481b36c03eSAdrian Hunter 22491b36c03eSAdrian Hunter static int parse_addr_size(char **inp, u64 *num, const char **str, int *idx) 22501b36c03eSAdrian Hunter { 22511b36c03eSAdrian Hunter int err = parse_num_or_str(inp, num, str, " "); 22521b36c03eSAdrian Hunter 22531b36c03eSAdrian Hunter if (!err && *str) 22541b36c03eSAdrian Hunter err = parse_sym_idx(inp, idx); 22551b36c03eSAdrian Hunter 22561b36c03eSAdrian Hunter return err; 22571b36c03eSAdrian Hunter } 22581b36c03eSAdrian Hunter 22591b36c03eSAdrian Hunter static int parse_one_filter(struct addr_filter *filt, const char **filter_inp) 22601b36c03eSAdrian Hunter { 22611b36c03eSAdrian Hunter char *fstr; 22621b36c03eSAdrian Hunter int err; 22631b36c03eSAdrian Hunter 22641b36c03eSAdrian Hunter filt->str = fstr = strdup(*filter_inp); 22651b36c03eSAdrian Hunter if (!fstr) 22661b36c03eSAdrian Hunter return -ENOMEM; 22671b36c03eSAdrian Hunter 22681b36c03eSAdrian Hunter err = parse_num_or_str(&fstr, NULL, &filt->action, " "); 22691b36c03eSAdrian Hunter if (err) 22701b36c03eSAdrian Hunter goto out_err; 22711b36c03eSAdrian Hunter 22721b36c03eSAdrian Hunter err = parse_action(filt); 22731b36c03eSAdrian Hunter if (err) 22741b36c03eSAdrian Hunter goto out_err; 22751b36c03eSAdrian Hunter 22761b36c03eSAdrian Hunter err = parse_addr_size(&fstr, &filt->addr, &filt->sym_from, 22771b36c03eSAdrian Hunter &filt->sym_from_idx); 22781b36c03eSAdrian Hunter if (err) 22791b36c03eSAdrian Hunter goto out_err; 22801b36c03eSAdrian Hunter 22811b36c03eSAdrian Hunter fstr += strspn(fstr, " "); 22821b36c03eSAdrian Hunter 22831b36c03eSAdrian Hunter if (*fstr == '/') { 22841b36c03eSAdrian Hunter fstr += 1; 22851b36c03eSAdrian Hunter err = parse_addr_size(&fstr, &filt->size, &filt->sym_to, 22861b36c03eSAdrian Hunter &filt->sym_to_idx); 22871b36c03eSAdrian Hunter if (err) 22881b36c03eSAdrian Hunter goto out_err; 22891b36c03eSAdrian Hunter filt->range = true; 22901b36c03eSAdrian Hunter } 22911b36c03eSAdrian Hunter 22921b36c03eSAdrian Hunter fstr += strspn(fstr, " "); 22931b36c03eSAdrian Hunter 22941b36c03eSAdrian Hunter if (*fstr == '@') { 22951b36c03eSAdrian Hunter fstr += 1; 22961b36c03eSAdrian Hunter err = parse_num_or_str(&fstr, NULL, &filt->filename, " ,"); 22971b36c03eSAdrian Hunter if (err) 22981b36c03eSAdrian Hunter goto out_err; 22991b36c03eSAdrian Hunter } 23001b36c03eSAdrian Hunter 23011b36c03eSAdrian Hunter fstr += strspn(fstr, " ,"); 23021b36c03eSAdrian Hunter 23031b36c03eSAdrian Hunter *filter_inp += fstr - filt->str; 23041b36c03eSAdrian Hunter 23051b36c03eSAdrian Hunter return 0; 23061b36c03eSAdrian Hunter 23071b36c03eSAdrian Hunter out_err: 23081b36c03eSAdrian Hunter addr_filter__free_str(filt); 23091b36c03eSAdrian Hunter 23101b36c03eSAdrian Hunter return err; 23111b36c03eSAdrian Hunter } 23121b36c03eSAdrian Hunter 23131b36c03eSAdrian Hunter int addr_filters__parse_bare_filter(struct addr_filters *filts, 23141b36c03eSAdrian Hunter const char *filter) 23151b36c03eSAdrian Hunter { 23161b36c03eSAdrian Hunter struct addr_filter *filt; 23171b36c03eSAdrian Hunter const char *fstr = filter; 23181b36c03eSAdrian Hunter int err; 23191b36c03eSAdrian Hunter 23201b36c03eSAdrian Hunter while (*fstr) { 23211b36c03eSAdrian Hunter filt = addr_filter__new(); 23221b36c03eSAdrian Hunter err = parse_one_filter(filt, &fstr); 23231b36c03eSAdrian Hunter if (err) { 23241b36c03eSAdrian Hunter addr_filter__free(filt); 23251b36c03eSAdrian Hunter addr_filters__exit(filts); 23261b36c03eSAdrian Hunter return err; 23271b36c03eSAdrian Hunter } 23281b36c03eSAdrian Hunter addr_filters__add(filts, filt); 23291b36c03eSAdrian Hunter } 23301b36c03eSAdrian Hunter 23311b36c03eSAdrian Hunter return 0; 23321b36c03eSAdrian Hunter } 23331b36c03eSAdrian Hunter 23341b36c03eSAdrian Hunter struct sym_args { 23351b36c03eSAdrian Hunter const char *name; 23361b36c03eSAdrian Hunter u64 start; 23371b36c03eSAdrian Hunter u64 size; 23381b36c03eSAdrian Hunter int idx; 23391b36c03eSAdrian Hunter int cnt; 23401b36c03eSAdrian Hunter bool started; 23411b36c03eSAdrian Hunter bool global; 23421b36c03eSAdrian Hunter bool selected; 23431b36c03eSAdrian Hunter bool duplicate; 23441b36c03eSAdrian Hunter bool near; 23451b36c03eSAdrian Hunter }; 23461b36c03eSAdrian Hunter 2347cba04f31SAdrian Hunter static bool kern_sym_name_match(const char *kname, const char *name) 2348cba04f31SAdrian Hunter { 2349cba04f31SAdrian Hunter size_t n = strlen(name); 2350cba04f31SAdrian Hunter 2351cba04f31SAdrian Hunter return !strcmp(kname, name) || 2352cba04f31SAdrian Hunter (!strncmp(kname, name, n) && kname[n] == '\t'); 2353cba04f31SAdrian Hunter } 2354cba04f31SAdrian Hunter 23551b36c03eSAdrian Hunter static bool kern_sym_match(struct sym_args *args, const char *name, char type) 23561b36c03eSAdrian Hunter { 23571b36c03eSAdrian Hunter /* A function with the same name, and global or the n'th found or any */ 2358e85e0e0cSArnaldo Carvalho de Melo return kallsyms__is_function(type) && 2359cba04f31SAdrian Hunter kern_sym_name_match(name, args->name) && 23601b36c03eSAdrian Hunter ((args->global && isupper(type)) || 23611b36c03eSAdrian Hunter (args->selected && ++(args->cnt) == args->idx) || 23621b36c03eSAdrian Hunter (!args->global && !args->selected)); 23631b36c03eSAdrian Hunter } 23641b36c03eSAdrian Hunter 23651b36c03eSAdrian Hunter static int find_kern_sym_cb(void *arg, const char *name, char type, u64 start) 23661b36c03eSAdrian Hunter { 23671b36c03eSAdrian Hunter struct sym_args *args = arg; 23681b36c03eSAdrian Hunter 23691b36c03eSAdrian Hunter if (args->started) { 23701b36c03eSAdrian Hunter if (!args->size) 23711b36c03eSAdrian Hunter args->size = start - args->start; 23721b36c03eSAdrian Hunter if (args->selected) { 23731b36c03eSAdrian Hunter if (args->size) 23741b36c03eSAdrian Hunter return 1; 23751b36c03eSAdrian Hunter } else if (kern_sym_match(args, name, type)) { 23761b36c03eSAdrian Hunter args->duplicate = true; 23771b36c03eSAdrian Hunter return 1; 23781b36c03eSAdrian Hunter } 23791b36c03eSAdrian Hunter } else if (kern_sym_match(args, name, type)) { 23801b36c03eSAdrian Hunter args->started = true; 23811b36c03eSAdrian Hunter args->start = start; 23821b36c03eSAdrian Hunter } 23831b36c03eSAdrian Hunter 23841b36c03eSAdrian Hunter return 0; 23851b36c03eSAdrian Hunter } 23861b36c03eSAdrian Hunter 23871b36c03eSAdrian Hunter static int print_kern_sym_cb(void *arg, const char *name, char type, u64 start) 23881b36c03eSAdrian Hunter { 23891b36c03eSAdrian Hunter struct sym_args *args = arg; 23901b36c03eSAdrian Hunter 23911b36c03eSAdrian Hunter if (kern_sym_match(args, name, type)) { 23921b36c03eSAdrian Hunter pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 23931b36c03eSAdrian Hunter ++args->cnt, start, type, name); 23941b36c03eSAdrian Hunter args->near = true; 23951b36c03eSAdrian Hunter } else if (args->near) { 23961b36c03eSAdrian Hunter args->near = false; 23971b36c03eSAdrian Hunter pr_err("\t\twhich is near\t\t%s\n", name); 23981b36c03eSAdrian Hunter } 23991b36c03eSAdrian Hunter 24001b36c03eSAdrian Hunter return 0; 24011b36c03eSAdrian Hunter } 24021b36c03eSAdrian Hunter 24031b36c03eSAdrian Hunter static int sym_not_found_error(const char *sym_name, int idx) 24041b36c03eSAdrian Hunter { 24051b36c03eSAdrian Hunter if (idx > 0) { 24061b36c03eSAdrian Hunter pr_err("N'th occurrence (N=%d) of symbol '%s' not found.\n", 24071b36c03eSAdrian Hunter idx, sym_name); 24081b36c03eSAdrian Hunter } else if (!idx) { 24091b36c03eSAdrian Hunter pr_err("Global symbol '%s' not found.\n", sym_name); 24101b36c03eSAdrian Hunter } else { 24111b36c03eSAdrian Hunter pr_err("Symbol '%s' not found.\n", sym_name); 24121b36c03eSAdrian Hunter } 24131b36c03eSAdrian Hunter pr_err("Note that symbols must be functions.\n"); 24141b36c03eSAdrian Hunter 24151b36c03eSAdrian Hunter return -EINVAL; 24161b36c03eSAdrian Hunter } 24171b36c03eSAdrian Hunter 24181b36c03eSAdrian Hunter static int find_kern_sym(const char *sym_name, u64 *start, u64 *size, int idx) 24191b36c03eSAdrian Hunter { 24201b36c03eSAdrian Hunter struct sym_args args = { 24211b36c03eSAdrian Hunter .name = sym_name, 24221b36c03eSAdrian Hunter .idx = idx, 24231b36c03eSAdrian Hunter .global = !idx, 24241b36c03eSAdrian Hunter .selected = idx > 0, 24251b36c03eSAdrian Hunter }; 24261b36c03eSAdrian Hunter int err; 24271b36c03eSAdrian Hunter 24281b36c03eSAdrian Hunter *start = 0; 24291b36c03eSAdrian Hunter *size = 0; 24301b36c03eSAdrian Hunter 24311b36c03eSAdrian Hunter err = kallsyms__parse("/proc/kallsyms", &args, find_kern_sym_cb); 24321b36c03eSAdrian Hunter if (err < 0) { 24331b36c03eSAdrian Hunter pr_err("Failed to parse /proc/kallsyms\n"); 24341b36c03eSAdrian Hunter return err; 24351b36c03eSAdrian Hunter } 24361b36c03eSAdrian Hunter 24371b36c03eSAdrian Hunter if (args.duplicate) { 24381b36c03eSAdrian Hunter pr_err("Multiple kernel symbols with name '%s'\n", sym_name); 24391b36c03eSAdrian Hunter args.cnt = 0; 24401b36c03eSAdrian Hunter kallsyms__parse("/proc/kallsyms", &args, print_kern_sym_cb); 24411b36c03eSAdrian Hunter pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 24421b36c03eSAdrian Hunter sym_name); 24431b36c03eSAdrian Hunter pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 24441b36c03eSAdrian Hunter return -EINVAL; 24451b36c03eSAdrian Hunter } 24461b36c03eSAdrian Hunter 24471b36c03eSAdrian Hunter if (!args.started) { 24481b36c03eSAdrian Hunter pr_err("Kernel symbol lookup: "); 24491b36c03eSAdrian Hunter return sym_not_found_error(sym_name, idx); 24501b36c03eSAdrian Hunter } 24511b36c03eSAdrian Hunter 24521b36c03eSAdrian Hunter *start = args.start; 24531b36c03eSAdrian Hunter *size = args.size; 24541b36c03eSAdrian Hunter 24551b36c03eSAdrian Hunter return 0; 24561b36c03eSAdrian Hunter } 24571b36c03eSAdrian Hunter 24581b36c03eSAdrian Hunter static int find_entire_kern_cb(void *arg, const char *name __maybe_unused, 24591b36c03eSAdrian Hunter char type, u64 start) 24601b36c03eSAdrian Hunter { 24611b36c03eSAdrian Hunter struct sym_args *args = arg; 24621f9f33ccSAdrian Hunter u64 size; 24631b36c03eSAdrian Hunter 2464e85e0e0cSArnaldo Carvalho de Melo if (!kallsyms__is_function(type)) 24651b36c03eSAdrian Hunter return 0; 24661b36c03eSAdrian Hunter 24671b36c03eSAdrian Hunter if (!args->started) { 24681b36c03eSAdrian Hunter args->started = true; 24691b36c03eSAdrian Hunter args->start = start; 24701b36c03eSAdrian Hunter } 24711b36c03eSAdrian Hunter /* Don't know exactly where the kernel ends, so we add a page */ 24721f9f33ccSAdrian Hunter size = round_up(start, page_size) + page_size - args->start; 24731f9f33ccSAdrian Hunter if (size > args->size) 24741f9f33ccSAdrian Hunter args->size = size; 24751b36c03eSAdrian Hunter 24761b36c03eSAdrian Hunter return 0; 24771b36c03eSAdrian Hunter } 24781b36c03eSAdrian Hunter 24791b36c03eSAdrian Hunter static int addr_filter__entire_kernel(struct addr_filter *filt) 24801b36c03eSAdrian Hunter { 24811b36c03eSAdrian Hunter struct sym_args args = { .started = false }; 24821b36c03eSAdrian Hunter int err; 24831b36c03eSAdrian Hunter 24841b36c03eSAdrian Hunter err = kallsyms__parse("/proc/kallsyms", &args, find_entire_kern_cb); 24851b36c03eSAdrian Hunter if (err < 0 || !args.started) { 24861b36c03eSAdrian Hunter pr_err("Failed to parse /proc/kallsyms\n"); 24871b36c03eSAdrian Hunter return err; 24881b36c03eSAdrian Hunter } 24891b36c03eSAdrian Hunter 24901b36c03eSAdrian Hunter filt->addr = args.start; 24911b36c03eSAdrian Hunter filt->size = args.size; 24921b36c03eSAdrian Hunter 24931b36c03eSAdrian Hunter return 0; 24941b36c03eSAdrian Hunter } 24951b36c03eSAdrian Hunter 24961b36c03eSAdrian Hunter static int check_end_after_start(struct addr_filter *filt, u64 start, u64 size) 24971b36c03eSAdrian Hunter { 24981b36c03eSAdrian Hunter if (start + size >= filt->addr) 24991b36c03eSAdrian Hunter return 0; 25001b36c03eSAdrian Hunter 25011b36c03eSAdrian Hunter if (filt->sym_from) { 25021b36c03eSAdrian Hunter pr_err("Symbol '%s' (0x%"PRIx64") comes before '%s' (0x%"PRIx64")\n", 25031b36c03eSAdrian Hunter filt->sym_to, start, filt->sym_from, filt->addr); 25041b36c03eSAdrian Hunter } else { 25051b36c03eSAdrian Hunter pr_err("Symbol '%s' (0x%"PRIx64") comes before address 0x%"PRIx64")\n", 25061b36c03eSAdrian Hunter filt->sym_to, start, filt->addr); 25071b36c03eSAdrian Hunter } 25081b36c03eSAdrian Hunter 25091b36c03eSAdrian Hunter return -EINVAL; 25101b36c03eSAdrian Hunter } 25111b36c03eSAdrian Hunter 25121b36c03eSAdrian Hunter static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) 25131b36c03eSAdrian Hunter { 25141b36c03eSAdrian Hunter bool no_size = false; 25151b36c03eSAdrian Hunter u64 start, size; 25161b36c03eSAdrian Hunter int err; 25171b36c03eSAdrian Hunter 25181b36c03eSAdrian Hunter if (symbol_conf.kptr_restrict) { 25191b36c03eSAdrian Hunter pr_err("Kernel addresses are restricted. Unable to resolve kernel symbols.\n"); 25201b36c03eSAdrian Hunter return -EINVAL; 25211b36c03eSAdrian Hunter } 25221b36c03eSAdrian Hunter 25231b36c03eSAdrian Hunter if (filt->sym_from && !strcmp(filt->sym_from, "*")) 25241b36c03eSAdrian Hunter return addr_filter__entire_kernel(filt); 25251b36c03eSAdrian Hunter 25261b36c03eSAdrian Hunter if (filt->sym_from) { 25271b36c03eSAdrian Hunter err = find_kern_sym(filt->sym_from, &start, &size, 25281b36c03eSAdrian Hunter filt->sym_from_idx); 25291b36c03eSAdrian Hunter if (err) 25301b36c03eSAdrian Hunter return err; 25311b36c03eSAdrian Hunter filt->addr = start; 25321b36c03eSAdrian Hunter if (filt->range && !filt->size && !filt->sym_to) { 25331b36c03eSAdrian Hunter filt->size = size; 2534c3a0bbc7SAdrian Hunter no_size = !size; 25351b36c03eSAdrian Hunter } 25361b36c03eSAdrian Hunter } 25371b36c03eSAdrian Hunter 25381b36c03eSAdrian Hunter if (filt->sym_to) { 25391b36c03eSAdrian Hunter err = find_kern_sym(filt->sym_to, &start, &size, 25401b36c03eSAdrian Hunter filt->sym_to_idx); 25411b36c03eSAdrian Hunter if (err) 25421b36c03eSAdrian Hunter return err; 25431b36c03eSAdrian Hunter 25441b36c03eSAdrian Hunter err = check_end_after_start(filt, start, size); 25451b36c03eSAdrian Hunter if (err) 25461b36c03eSAdrian Hunter return err; 25471b36c03eSAdrian Hunter filt->size = start + size - filt->addr; 2548c3a0bbc7SAdrian Hunter no_size = !size; 25491b36c03eSAdrian Hunter } 25501b36c03eSAdrian Hunter 25511b36c03eSAdrian Hunter /* The very last symbol in kallsyms does not imply a particular size */ 25521b36c03eSAdrian Hunter if (no_size) { 25531b36c03eSAdrian Hunter pr_err("Cannot determine size of symbol '%s'\n", 25541b36c03eSAdrian Hunter filt->sym_to ? filt->sym_to : filt->sym_from); 25551b36c03eSAdrian Hunter return -EINVAL; 25561b36c03eSAdrian Hunter } 25571b36c03eSAdrian Hunter 25581b36c03eSAdrian Hunter return 0; 25591b36c03eSAdrian Hunter } 25601b36c03eSAdrian Hunter 25611b36c03eSAdrian Hunter static struct dso *load_dso(const char *name) 25621b36c03eSAdrian Hunter { 25631b36c03eSAdrian Hunter struct map *map; 25641b36c03eSAdrian Hunter struct dso *dso; 25651b36c03eSAdrian Hunter 25661b36c03eSAdrian Hunter map = dso__new_map(name); 25671b36c03eSAdrian Hunter if (!map) 25681b36c03eSAdrian Hunter return NULL; 25691b36c03eSAdrian Hunter 2570c1c49204SAdrian Hunter if (map__load(map) < 0) 2571c1c49204SAdrian Hunter pr_err("File '%s' not found or has no symbols.\n", name); 25721b36c03eSAdrian Hunter 257363df0e4bSIan Rogers dso = dso__get(map__dso(map)); 25741b36c03eSAdrian Hunter 25751b36c03eSAdrian Hunter map__put(map); 25761b36c03eSAdrian Hunter 25771b36c03eSAdrian Hunter return dso; 25781b36c03eSAdrian Hunter } 25791b36c03eSAdrian Hunter 25801b36c03eSAdrian Hunter static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt, 25811b36c03eSAdrian Hunter int idx) 25821b36c03eSAdrian Hunter { 25831b36c03eSAdrian Hunter /* Same name, and global or the n'th found or any */ 25841b36c03eSAdrian Hunter return !arch__compare_symbol_names(name, sym->name) && 25851b36c03eSAdrian Hunter ((!idx && sym->binding == STB_GLOBAL) || 25861b36c03eSAdrian Hunter (idx > 0 && ++*cnt == idx) || 25871b36c03eSAdrian Hunter idx < 0); 25881b36c03eSAdrian Hunter } 25891b36c03eSAdrian Hunter 25901b36c03eSAdrian Hunter static void print_duplicate_syms(struct dso *dso, const char *sym_name) 25911b36c03eSAdrian Hunter { 25921b36c03eSAdrian Hunter struct symbol *sym; 25931b36c03eSAdrian Hunter bool near = false; 25941b36c03eSAdrian Hunter int cnt = 0; 25951b36c03eSAdrian Hunter 25961b36c03eSAdrian Hunter pr_err("Multiple symbols with name '%s'\n", sym_name); 25971b36c03eSAdrian Hunter 25985cf88a63SArnaldo Carvalho de Melo sym = dso__first_symbol(dso); 25991b36c03eSAdrian Hunter while (sym) { 26001b36c03eSAdrian Hunter if (dso_sym_match(sym, sym_name, &cnt, -1)) { 26011b36c03eSAdrian Hunter pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 26021b36c03eSAdrian Hunter ++cnt, sym->start, 26031b36c03eSAdrian Hunter sym->binding == STB_GLOBAL ? 'g' : 26041b36c03eSAdrian Hunter sym->binding == STB_LOCAL ? 'l' : 'w', 26051b36c03eSAdrian Hunter sym->name); 26061b36c03eSAdrian Hunter near = true; 26071b36c03eSAdrian Hunter } else if (near) { 26081b36c03eSAdrian Hunter near = false; 26091b36c03eSAdrian Hunter pr_err("\t\twhich is near\t\t%s\n", sym->name); 26101b36c03eSAdrian Hunter } 26111b36c03eSAdrian Hunter sym = dso__next_symbol(sym); 26121b36c03eSAdrian Hunter } 26131b36c03eSAdrian Hunter 26141b36c03eSAdrian Hunter pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 26151b36c03eSAdrian Hunter sym_name); 26161b36c03eSAdrian Hunter pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 26171b36c03eSAdrian Hunter } 26181b36c03eSAdrian Hunter 26191b36c03eSAdrian Hunter static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start, 26201b36c03eSAdrian Hunter u64 *size, int idx) 26211b36c03eSAdrian Hunter { 26221b36c03eSAdrian Hunter struct symbol *sym; 26231b36c03eSAdrian Hunter int cnt = 0; 26241b36c03eSAdrian Hunter 26251b36c03eSAdrian Hunter *start = 0; 26261b36c03eSAdrian Hunter *size = 0; 26271b36c03eSAdrian Hunter 26285cf88a63SArnaldo Carvalho de Melo sym = dso__first_symbol(dso); 26291b36c03eSAdrian Hunter while (sym) { 26301b36c03eSAdrian Hunter if (*start) { 26311b36c03eSAdrian Hunter if (!*size) 26321b36c03eSAdrian Hunter *size = sym->start - *start; 26331b36c03eSAdrian Hunter if (idx > 0) { 26341b36c03eSAdrian Hunter if (*size) 2635cf129830SAdrian Hunter return 0; 26361b36c03eSAdrian Hunter } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 26371b36c03eSAdrian Hunter print_duplicate_syms(dso, sym_name); 26381b36c03eSAdrian Hunter return -EINVAL; 26391b36c03eSAdrian Hunter } 26401b36c03eSAdrian Hunter } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 26411b36c03eSAdrian Hunter *start = sym->start; 26421b36c03eSAdrian Hunter *size = sym->end - sym->start; 26431b36c03eSAdrian Hunter } 26441b36c03eSAdrian Hunter sym = dso__next_symbol(sym); 26451b36c03eSAdrian Hunter } 26461b36c03eSAdrian Hunter 26471b36c03eSAdrian Hunter if (!*start) 26481b36c03eSAdrian Hunter return sym_not_found_error(sym_name, idx); 26491b36c03eSAdrian Hunter 26501b36c03eSAdrian Hunter return 0; 26511b36c03eSAdrian Hunter } 26521b36c03eSAdrian Hunter 26531b36c03eSAdrian Hunter static int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso) 26541b36c03eSAdrian Hunter { 265557176601SAdrian Hunter if (dso__data_file_size(dso, NULL)) { 265657176601SAdrian Hunter pr_err("Failed to determine filter for %s\nCannot determine file size.\n", 26571b36c03eSAdrian Hunter filt->filename); 26581b36c03eSAdrian Hunter return -EINVAL; 26591b36c03eSAdrian Hunter } 26601b36c03eSAdrian Hunter 266157176601SAdrian Hunter filt->addr = 0; 2662ee756ef7SIan Rogers filt->size = dso__data(dso)->file_size; 26631b36c03eSAdrian Hunter 26641b36c03eSAdrian Hunter return 0; 26651b36c03eSAdrian Hunter } 26661b36c03eSAdrian Hunter 26671b36c03eSAdrian Hunter static int addr_filter__resolve_syms(struct addr_filter *filt) 26681b36c03eSAdrian Hunter { 26691b36c03eSAdrian Hunter u64 start, size; 26701b36c03eSAdrian Hunter struct dso *dso; 26711b36c03eSAdrian Hunter int err = 0; 26721b36c03eSAdrian Hunter 26731b36c03eSAdrian Hunter if (!filt->sym_from && !filt->sym_to) 26741b36c03eSAdrian Hunter return 0; 26751b36c03eSAdrian Hunter 26761b36c03eSAdrian Hunter if (!filt->filename) 26771b36c03eSAdrian Hunter return addr_filter__resolve_kernel_syms(filt); 26781b36c03eSAdrian Hunter 26791b36c03eSAdrian Hunter dso = load_dso(filt->filename); 26801b36c03eSAdrian Hunter if (!dso) { 26811b36c03eSAdrian Hunter pr_err("Failed to load symbols from: %s\n", filt->filename); 26821b36c03eSAdrian Hunter return -EINVAL; 26831b36c03eSAdrian Hunter } 26841b36c03eSAdrian Hunter 26851b36c03eSAdrian Hunter if (filt->sym_from && !strcmp(filt->sym_from, "*")) { 26861b36c03eSAdrian Hunter err = addr_filter__entire_dso(filt, dso); 26871b36c03eSAdrian Hunter goto put_dso; 26881b36c03eSAdrian Hunter } 26891b36c03eSAdrian Hunter 26901b36c03eSAdrian Hunter if (filt->sym_from) { 26911b36c03eSAdrian Hunter err = find_dso_sym(dso, filt->sym_from, &start, &size, 26921b36c03eSAdrian Hunter filt->sym_from_idx); 26931b36c03eSAdrian Hunter if (err) 26941b36c03eSAdrian Hunter goto put_dso; 26951b36c03eSAdrian Hunter filt->addr = start; 26961b36c03eSAdrian Hunter if (filt->range && !filt->size && !filt->sym_to) 26971b36c03eSAdrian Hunter filt->size = size; 26981b36c03eSAdrian Hunter } 26991b36c03eSAdrian Hunter 27001b36c03eSAdrian Hunter if (filt->sym_to) { 27011b36c03eSAdrian Hunter err = find_dso_sym(dso, filt->sym_to, &start, &size, 27021b36c03eSAdrian Hunter filt->sym_to_idx); 27031b36c03eSAdrian Hunter if (err) 27041b36c03eSAdrian Hunter goto put_dso; 27051b36c03eSAdrian Hunter 27061b36c03eSAdrian Hunter err = check_end_after_start(filt, start, size); 27071b36c03eSAdrian Hunter if (err) 27081b36c03eSAdrian Hunter return err; 27091b36c03eSAdrian Hunter 27101b36c03eSAdrian Hunter filt->size = start + size - filt->addr; 27111b36c03eSAdrian Hunter } 27121b36c03eSAdrian Hunter 27131b36c03eSAdrian Hunter put_dso: 27141b36c03eSAdrian Hunter dso__put(dso); 27151b36c03eSAdrian Hunter 27161b36c03eSAdrian Hunter return err; 27171b36c03eSAdrian Hunter } 27181b36c03eSAdrian Hunter 27191b36c03eSAdrian Hunter static char *addr_filter__to_str(struct addr_filter *filt) 27201b36c03eSAdrian Hunter { 27211b36c03eSAdrian Hunter char filename_buf[PATH_MAX]; 27221b36c03eSAdrian Hunter const char *at = ""; 27231b36c03eSAdrian Hunter const char *fn = ""; 27241b36c03eSAdrian Hunter char *filter; 27251b36c03eSAdrian Hunter int err; 27261b36c03eSAdrian Hunter 27271b36c03eSAdrian Hunter if (filt->filename) { 27281b36c03eSAdrian Hunter at = "@"; 27291b36c03eSAdrian Hunter fn = realpath(filt->filename, filename_buf); 27301b36c03eSAdrian Hunter if (!fn) 27311b36c03eSAdrian Hunter return NULL; 27321b36c03eSAdrian Hunter } 27331b36c03eSAdrian Hunter 27341b36c03eSAdrian Hunter if (filt->range) { 27351b36c03eSAdrian Hunter err = asprintf(&filter, "%s 0x%"PRIx64"/0x%"PRIx64"%s%s", 27361b36c03eSAdrian Hunter filt->action, filt->addr, filt->size, at, fn); 27371b36c03eSAdrian Hunter } else { 27381b36c03eSAdrian Hunter err = asprintf(&filter, "%s 0x%"PRIx64"%s%s", 27391b36c03eSAdrian Hunter filt->action, filt->addr, at, fn); 27401b36c03eSAdrian Hunter } 27411b36c03eSAdrian Hunter 27421b36c03eSAdrian Hunter return err < 0 ? NULL : filter; 27431b36c03eSAdrian Hunter } 27441b36c03eSAdrian Hunter 274532dcd021SJiri Olsa static int parse_addr_filter(struct evsel *evsel, const char *filter, 27461b36c03eSAdrian Hunter int max_nr) 27471b36c03eSAdrian Hunter { 27481b36c03eSAdrian Hunter struct addr_filters filts; 27491b36c03eSAdrian Hunter struct addr_filter *filt; 27501b36c03eSAdrian Hunter int err; 27511b36c03eSAdrian Hunter 27521b36c03eSAdrian Hunter addr_filters__init(&filts); 27531b36c03eSAdrian Hunter 27541b36c03eSAdrian Hunter err = addr_filters__parse_bare_filter(&filts, filter); 27551b36c03eSAdrian Hunter if (err) 27561b36c03eSAdrian Hunter goto out_exit; 27571b36c03eSAdrian Hunter 27581b36c03eSAdrian Hunter if (filts.cnt > max_nr) { 27591b36c03eSAdrian Hunter pr_err("Error: number of address filters (%d) exceeds maximum (%d)\n", 27601b36c03eSAdrian Hunter filts.cnt, max_nr); 27611b36c03eSAdrian Hunter err = -EINVAL; 27621b36c03eSAdrian Hunter goto out_exit; 27631b36c03eSAdrian Hunter } 27641b36c03eSAdrian Hunter 27651b36c03eSAdrian Hunter list_for_each_entry(filt, &filts.head, list) { 27661b36c03eSAdrian Hunter char *new_filter; 27671b36c03eSAdrian Hunter 27681b36c03eSAdrian Hunter err = addr_filter__resolve_syms(filt); 27691b36c03eSAdrian Hunter if (err) 27701b36c03eSAdrian Hunter goto out_exit; 27711b36c03eSAdrian Hunter 27721b36c03eSAdrian Hunter new_filter = addr_filter__to_str(filt); 27731b36c03eSAdrian Hunter if (!new_filter) { 27741b36c03eSAdrian Hunter err = -ENOMEM; 27751b36c03eSAdrian Hunter goto out_exit; 27761b36c03eSAdrian Hunter } 27771b36c03eSAdrian Hunter 2778ad681adfSArnaldo Carvalho de Melo if (evsel__append_addr_filter(evsel, new_filter)) { 27791b36c03eSAdrian Hunter err = -ENOMEM; 27801b36c03eSAdrian Hunter goto out_exit; 27811b36c03eSAdrian Hunter } 27821b36c03eSAdrian Hunter } 27831b36c03eSAdrian Hunter 27841b36c03eSAdrian Hunter out_exit: 27851b36c03eSAdrian Hunter addr_filters__exit(&filts); 27861b36c03eSAdrian Hunter 27871b36c03eSAdrian Hunter if (err) { 27881b36c03eSAdrian Hunter pr_err("Failed to parse address filter: '%s'\n", filter); 27891b36c03eSAdrian Hunter pr_err("Filter format is: filter|start|stop|tracestop <start symbol or address> [/ <end symbol or size>] [@<file name>]\n"); 27901b36c03eSAdrian Hunter pr_err("Where multiple filters are separated by space or comma.\n"); 27911b36c03eSAdrian Hunter } 27921b36c03eSAdrian Hunter 27931b36c03eSAdrian Hunter return err; 27941b36c03eSAdrian Hunter } 27951b36c03eSAdrian Hunter 2796ad681adfSArnaldo Carvalho de Melo static int evsel__nr_addr_filter(struct evsel *evsel) 27971b36c03eSAdrian Hunter { 2798e76026bdSArnaldo Carvalho de Melo struct perf_pmu *pmu = evsel__find_pmu(evsel); 27991b36c03eSAdrian Hunter int nr_addr_filters = 0; 28001b36c03eSAdrian Hunter 28011b36c03eSAdrian Hunter if (!pmu) 28021b36c03eSAdrian Hunter return 0; 28031b36c03eSAdrian Hunter 28041b36c03eSAdrian Hunter perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters); 28051b36c03eSAdrian Hunter 28061b36c03eSAdrian Hunter return nr_addr_filters; 28071b36c03eSAdrian Hunter } 28081b36c03eSAdrian Hunter 280963503dbaSJiri Olsa int auxtrace_parse_filters(struct evlist *evlist) 28101b36c03eSAdrian Hunter { 281132dcd021SJiri Olsa struct evsel *evsel; 28121b36c03eSAdrian Hunter char *filter; 28131b36c03eSAdrian Hunter int err, max_nr; 28141b36c03eSAdrian Hunter 28151b36c03eSAdrian Hunter evlist__for_each_entry(evlist, evsel) { 28161b36c03eSAdrian Hunter filter = evsel->filter; 2817ad681adfSArnaldo Carvalho de Melo max_nr = evsel__nr_addr_filter(evsel); 28181b36c03eSAdrian Hunter if (!filter || !max_nr) 28191b36c03eSAdrian Hunter continue; 28201b36c03eSAdrian Hunter evsel->filter = NULL; 28211b36c03eSAdrian Hunter err = parse_addr_filter(evsel, filter, max_nr); 28221b36c03eSAdrian Hunter free(filter); 28231b36c03eSAdrian Hunter if (err) 28241b36c03eSAdrian Hunter return err; 28251b36c03eSAdrian Hunter pr_debug("Address filter: %s\n", evsel->filter); 28261b36c03eSAdrian Hunter } 28271b36c03eSAdrian Hunter 28281b36c03eSAdrian Hunter return 0; 28291b36c03eSAdrian Hunter } 2830f2a39fe8SArnaldo Carvalho de Melo 2831f2a39fe8SArnaldo Carvalho de Melo int auxtrace__process_event(struct perf_session *session, union perf_event *event, 2832f2a39fe8SArnaldo Carvalho de Melo struct perf_sample *sample, struct perf_tool *tool) 2833f2a39fe8SArnaldo Carvalho de Melo { 2834f2a39fe8SArnaldo Carvalho de Melo if (!session->auxtrace) 2835f2a39fe8SArnaldo Carvalho de Melo return 0; 2836f2a39fe8SArnaldo Carvalho de Melo 2837f2a39fe8SArnaldo Carvalho de Melo return session->auxtrace->process_event(session, event, sample, tool); 2838f2a39fe8SArnaldo Carvalho de Melo } 2839f2a39fe8SArnaldo Carvalho de Melo 2840b04b8dd1SAdrian Hunter void auxtrace__dump_auxtrace_sample(struct perf_session *session, 2841b04b8dd1SAdrian Hunter struct perf_sample *sample) 2842b04b8dd1SAdrian Hunter { 2843b04b8dd1SAdrian Hunter if (!session->auxtrace || !session->auxtrace->dump_auxtrace_sample || 2844b04b8dd1SAdrian Hunter auxtrace__dont_decode(session)) 2845b04b8dd1SAdrian Hunter return; 2846b04b8dd1SAdrian Hunter 2847b04b8dd1SAdrian Hunter session->auxtrace->dump_auxtrace_sample(session, sample); 2848b04b8dd1SAdrian Hunter } 2849b04b8dd1SAdrian Hunter 2850f2a39fe8SArnaldo Carvalho de Melo int auxtrace__flush_events(struct perf_session *session, struct perf_tool *tool) 2851f2a39fe8SArnaldo Carvalho de Melo { 2852f2a39fe8SArnaldo Carvalho de Melo if (!session->auxtrace) 2853f2a39fe8SArnaldo Carvalho de Melo return 0; 2854f2a39fe8SArnaldo Carvalho de Melo 2855f2a39fe8SArnaldo Carvalho de Melo return session->auxtrace->flush_events(session, tool); 2856f2a39fe8SArnaldo Carvalho de Melo } 2857f2a39fe8SArnaldo Carvalho de Melo 2858f2a39fe8SArnaldo Carvalho de Melo void auxtrace__free_events(struct perf_session *session) 2859f2a39fe8SArnaldo Carvalho de Melo { 2860f2a39fe8SArnaldo Carvalho de Melo if (!session->auxtrace) 2861f2a39fe8SArnaldo Carvalho de Melo return; 2862f2a39fe8SArnaldo Carvalho de Melo 2863f2a39fe8SArnaldo Carvalho de Melo return session->auxtrace->free_events(session); 2864f2a39fe8SArnaldo Carvalho de Melo } 2865f2a39fe8SArnaldo Carvalho de Melo 2866f2a39fe8SArnaldo Carvalho de Melo void auxtrace__free(struct perf_session *session) 2867f2a39fe8SArnaldo Carvalho de Melo { 2868f2a39fe8SArnaldo Carvalho de Melo if (!session->auxtrace) 2869f2a39fe8SArnaldo Carvalho de Melo return; 2870f2a39fe8SArnaldo Carvalho de Melo 2871f2a39fe8SArnaldo Carvalho de Melo return session->auxtrace->free(session); 2872f2a39fe8SArnaldo Carvalho de Melo } 2873853f37d7SAdrian Hunter 2874853f37d7SAdrian Hunter bool auxtrace__evsel_is_auxtrace(struct perf_session *session, 2875853f37d7SAdrian Hunter struct evsel *evsel) 2876853f37d7SAdrian Hunter { 2877853f37d7SAdrian Hunter if (!session->auxtrace || !session->auxtrace->evsel_is_auxtrace) 2878853f37d7SAdrian Hunter return false; 2879853f37d7SAdrian Hunter 2880853f37d7SAdrian Hunter return session->auxtrace->evsel_is_auxtrace(session, evsel); 2881853f37d7SAdrian Hunter } 2882