1718c602dSAdrian Hunter /* 2718c602dSAdrian Hunter * auxtrace.c: AUX area trace support 3718c602dSAdrian Hunter * Copyright (c) 2013-2015, Intel Corporation. 4718c602dSAdrian Hunter * 5718c602dSAdrian Hunter * This program is free software; you can redistribute it and/or modify it 6718c602dSAdrian Hunter * under the terms and conditions of the GNU General Public License, 7718c602dSAdrian Hunter * version 2, as published by the Free Software Foundation. 8718c602dSAdrian Hunter * 9718c602dSAdrian Hunter * This program is distributed in the hope it will be useful, but WITHOUT 10718c602dSAdrian Hunter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11718c602dSAdrian Hunter * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 12718c602dSAdrian Hunter * more details. 13718c602dSAdrian Hunter * 14718c602dSAdrian Hunter */ 15718c602dSAdrian Hunter 16fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 17718c602dSAdrian Hunter #include <sys/types.h> 18718c602dSAdrian Hunter #include <sys/mman.h> 19718c602dSAdrian Hunter #include <stdbool.h> 201b36c03eSAdrian Hunter #include <string.h> 211b36c03eSAdrian Hunter #include <limits.h> 221b36c03eSAdrian Hunter #include <errno.h> 23718c602dSAdrian Hunter 24718c602dSAdrian Hunter #include <linux/kernel.h> 25718c602dSAdrian Hunter #include <linux/perf_event.h> 26718c602dSAdrian Hunter #include <linux/types.h> 27718c602dSAdrian Hunter #include <linux/bitops.h> 28718c602dSAdrian Hunter #include <linux/log2.h> 29e5027893SAdrian Hunter #include <linux/string.h> 30718c602dSAdrian Hunter 31e5027893SAdrian Hunter #include <sys/param.h> 329e0cc4feSAdrian Hunter #include <stdlib.h> 3385ed4729SAdrian Hunter #include <stdio.h> 34e5027893SAdrian Hunter #include <linux/list.h> 359e0cc4feSAdrian Hunter 36718c602dSAdrian Hunter #include "../perf.h" 37718c602dSAdrian Hunter #include "util.h" 38718c602dSAdrian Hunter #include "evlist.h" 391b36c03eSAdrian Hunter #include "dso.h" 401b36c03eSAdrian Hunter #include "map.h" 411b36c03eSAdrian Hunter #include "pmu.h" 421b36c03eSAdrian Hunter #include "evsel.h" 43718c602dSAdrian Hunter #include "cpumap.h" 44718c602dSAdrian Hunter #include "thread_map.h" 45718c602dSAdrian Hunter #include "asm/bug.h" 46718c602dSAdrian Hunter #include "auxtrace.h" 47718c602dSAdrian Hunter 48c3278f02SAdrian Hunter #include <linux/hash.h> 49c3278f02SAdrian Hunter 509e0cc4feSAdrian Hunter #include "event.h" 5185ed4729SAdrian Hunter #include "session.h" 529e0cc4feSAdrian Hunter #include "debug.h" 534b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 549e0cc4feSAdrian Hunter 55440a23b3SMathieu Poirier #include "cs-etm.h" 565efb1d54SAdrian Hunter #include "intel-pt.h" 57d0170af7SAdrian Hunter #include "intel-bts.h" 58ffd3d18cSKim Phillips #include "arm-spe.h" 59b96e6615SThomas Richter #include "s390-cpumsf.h" 605efb1d54SAdrian Hunter 613d689ed6SArnaldo Carvalho de Melo #include "sane_ctype.h" 623d689ed6SArnaldo Carvalho de Melo #include "symbol/kallsyms.h" 633d689ed6SArnaldo Carvalho de Melo 642e2967f4SAdrian Hunter static bool auxtrace__dont_decode(struct perf_session *session) 652e2967f4SAdrian Hunter { 662e2967f4SAdrian Hunter return !session->itrace_synth_opts || 672e2967f4SAdrian Hunter session->itrace_synth_opts->dont_decode; 682e2967f4SAdrian Hunter } 692e2967f4SAdrian Hunter 70718c602dSAdrian Hunter int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, 71718c602dSAdrian Hunter struct auxtrace_mmap_params *mp, 72718c602dSAdrian Hunter void *userpg, int fd) 73718c602dSAdrian Hunter { 74718c602dSAdrian Hunter struct perf_event_mmap_page *pc = userpg; 75718c602dSAdrian Hunter 76718c602dSAdrian Hunter WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n"); 77718c602dSAdrian Hunter 78718c602dSAdrian Hunter mm->userpg = userpg; 79718c602dSAdrian Hunter mm->mask = mp->mask; 80718c602dSAdrian Hunter mm->len = mp->len; 81718c602dSAdrian Hunter mm->prev = 0; 82718c602dSAdrian Hunter mm->idx = mp->idx; 83718c602dSAdrian Hunter mm->tid = mp->tid; 84718c602dSAdrian Hunter mm->cpu = mp->cpu; 85718c602dSAdrian Hunter 86718c602dSAdrian Hunter if (!mp->len) { 87718c602dSAdrian Hunter mm->base = NULL; 88718c602dSAdrian Hunter return 0; 89718c602dSAdrian Hunter } 90718c602dSAdrian Hunter 91a7fde09aSAdrian Hunter #if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT) 92a7fde09aSAdrian Hunter pr_err("Cannot use AUX area tracing mmaps\n"); 93a7fde09aSAdrian Hunter return -1; 94a7fde09aSAdrian Hunter #endif 95a7fde09aSAdrian Hunter 96718c602dSAdrian Hunter pc->aux_offset = mp->offset; 97718c602dSAdrian Hunter pc->aux_size = mp->len; 98718c602dSAdrian Hunter 99718c602dSAdrian Hunter mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset); 100718c602dSAdrian Hunter if (mm->base == MAP_FAILED) { 101718c602dSAdrian Hunter pr_debug2("failed to mmap AUX area\n"); 102718c602dSAdrian Hunter mm->base = NULL; 103718c602dSAdrian Hunter return -1; 104718c602dSAdrian Hunter } 105718c602dSAdrian Hunter 106718c602dSAdrian Hunter return 0; 107718c602dSAdrian Hunter } 108718c602dSAdrian Hunter 109718c602dSAdrian Hunter void auxtrace_mmap__munmap(struct auxtrace_mmap *mm) 110718c602dSAdrian Hunter { 111718c602dSAdrian Hunter if (mm->base) { 112718c602dSAdrian Hunter munmap(mm->base, mm->len); 113718c602dSAdrian Hunter mm->base = NULL; 114718c602dSAdrian Hunter } 115718c602dSAdrian Hunter } 116718c602dSAdrian Hunter 117718c602dSAdrian Hunter void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, 118718c602dSAdrian Hunter off_t auxtrace_offset, 119718c602dSAdrian Hunter unsigned int auxtrace_pages, 120718c602dSAdrian Hunter bool auxtrace_overwrite) 121718c602dSAdrian Hunter { 122718c602dSAdrian Hunter if (auxtrace_pages) { 123718c602dSAdrian Hunter mp->offset = auxtrace_offset; 124718c602dSAdrian Hunter mp->len = auxtrace_pages * (size_t)page_size; 125718c602dSAdrian Hunter mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0; 126718c602dSAdrian Hunter mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE); 127718c602dSAdrian Hunter pr_debug2("AUX area mmap length %zu\n", mp->len); 128718c602dSAdrian Hunter } else { 129718c602dSAdrian Hunter mp->len = 0; 130718c602dSAdrian Hunter } 131718c602dSAdrian Hunter } 132718c602dSAdrian Hunter 133718c602dSAdrian Hunter void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, 134718c602dSAdrian Hunter struct perf_evlist *evlist, int idx, 135718c602dSAdrian Hunter bool per_cpu) 136718c602dSAdrian Hunter { 137718c602dSAdrian Hunter mp->idx = idx; 138718c602dSAdrian Hunter 139718c602dSAdrian Hunter if (per_cpu) { 140718c602dSAdrian Hunter mp->cpu = evlist->cpus->map[idx]; 141718c602dSAdrian Hunter if (evlist->threads) 142e13798c7SJiri Olsa mp->tid = thread_map__pid(evlist->threads, 0); 143718c602dSAdrian Hunter else 144718c602dSAdrian Hunter mp->tid = -1; 145718c602dSAdrian Hunter } else { 146718c602dSAdrian Hunter mp->cpu = -1; 147e13798c7SJiri Olsa mp->tid = thread_map__pid(evlist->threads, idx); 148718c602dSAdrian Hunter } 149718c602dSAdrian Hunter } 1509e0cc4feSAdrian Hunter 151e5027893SAdrian Hunter #define AUXTRACE_INIT_NR_QUEUES 32 152e5027893SAdrian Hunter 153e5027893SAdrian Hunter static struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues) 154e5027893SAdrian Hunter { 155e5027893SAdrian Hunter struct auxtrace_queue *queue_array; 156e5027893SAdrian Hunter unsigned int max_nr_queues, i; 157e5027893SAdrian Hunter 158e5027893SAdrian Hunter max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue); 159e5027893SAdrian Hunter if (nr_queues > max_nr_queues) 160e5027893SAdrian Hunter return NULL; 161e5027893SAdrian Hunter 162e5027893SAdrian Hunter queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue)); 163e5027893SAdrian Hunter if (!queue_array) 164e5027893SAdrian Hunter return NULL; 165e5027893SAdrian Hunter 166e5027893SAdrian Hunter for (i = 0; i < nr_queues; i++) { 167e5027893SAdrian Hunter INIT_LIST_HEAD(&queue_array[i].head); 168e5027893SAdrian Hunter queue_array[i].priv = NULL; 169e5027893SAdrian Hunter } 170e5027893SAdrian Hunter 171e5027893SAdrian Hunter return queue_array; 172e5027893SAdrian Hunter } 173e5027893SAdrian Hunter 174e5027893SAdrian Hunter int auxtrace_queues__init(struct auxtrace_queues *queues) 175e5027893SAdrian Hunter { 176e5027893SAdrian Hunter queues->nr_queues = AUXTRACE_INIT_NR_QUEUES; 177e5027893SAdrian Hunter queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues); 178e5027893SAdrian Hunter if (!queues->queue_array) 179e5027893SAdrian Hunter return -ENOMEM; 180e5027893SAdrian Hunter return 0; 181e5027893SAdrian Hunter } 182e5027893SAdrian Hunter 183e5027893SAdrian Hunter static int auxtrace_queues__grow(struct auxtrace_queues *queues, 184e5027893SAdrian Hunter unsigned int new_nr_queues) 185e5027893SAdrian Hunter { 186e5027893SAdrian Hunter unsigned int nr_queues = queues->nr_queues; 187e5027893SAdrian Hunter struct auxtrace_queue *queue_array; 188e5027893SAdrian Hunter unsigned int i; 189e5027893SAdrian Hunter 190e5027893SAdrian Hunter if (!nr_queues) 191e5027893SAdrian Hunter nr_queues = AUXTRACE_INIT_NR_QUEUES; 192e5027893SAdrian Hunter 193e5027893SAdrian Hunter while (nr_queues && nr_queues < new_nr_queues) 194e5027893SAdrian Hunter nr_queues <<= 1; 195e5027893SAdrian Hunter 196e5027893SAdrian Hunter if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues) 197e5027893SAdrian Hunter return -EINVAL; 198e5027893SAdrian Hunter 199e5027893SAdrian Hunter queue_array = auxtrace_alloc_queue_array(nr_queues); 200e5027893SAdrian Hunter if (!queue_array) 201e5027893SAdrian Hunter return -ENOMEM; 202e5027893SAdrian Hunter 203e5027893SAdrian Hunter for (i = 0; i < queues->nr_queues; i++) { 204e5027893SAdrian Hunter list_splice_tail(&queues->queue_array[i].head, 205e5027893SAdrian Hunter &queue_array[i].head); 20699cbbe56SAdrian Hunter queue_array[i].tid = queues->queue_array[i].tid; 20799cbbe56SAdrian Hunter queue_array[i].cpu = queues->queue_array[i].cpu; 20899cbbe56SAdrian Hunter queue_array[i].set = queues->queue_array[i].set; 209e5027893SAdrian Hunter queue_array[i].priv = queues->queue_array[i].priv; 210e5027893SAdrian Hunter } 211e5027893SAdrian Hunter 212e5027893SAdrian Hunter queues->nr_queues = nr_queues; 213e5027893SAdrian Hunter queues->queue_array = queue_array; 214e5027893SAdrian Hunter 215e5027893SAdrian Hunter return 0; 216e5027893SAdrian Hunter } 217e5027893SAdrian Hunter 218e5027893SAdrian Hunter static void *auxtrace_copy_data(u64 size, struct perf_session *session) 219e5027893SAdrian Hunter { 2208ceb41d7SJiri Olsa int fd = perf_data__fd(session->data); 221e5027893SAdrian Hunter void *p; 222e5027893SAdrian Hunter ssize_t ret; 223e5027893SAdrian Hunter 224e5027893SAdrian Hunter if (size > SSIZE_MAX) 225e5027893SAdrian Hunter return NULL; 226e5027893SAdrian Hunter 227e5027893SAdrian Hunter p = malloc(size); 228e5027893SAdrian Hunter if (!p) 229e5027893SAdrian Hunter return NULL; 230e5027893SAdrian Hunter 231e5027893SAdrian Hunter ret = readn(fd, p, size); 232e5027893SAdrian Hunter if (ret != (ssize_t)size) { 233e5027893SAdrian Hunter free(p); 234e5027893SAdrian Hunter return NULL; 235e5027893SAdrian Hunter } 236e5027893SAdrian Hunter 237e5027893SAdrian Hunter return p; 238e5027893SAdrian Hunter } 239e5027893SAdrian Hunter 240a356a597SAdrian Hunter static int auxtrace_queues__queue_buffer(struct auxtrace_queues *queues, 241e5027893SAdrian Hunter unsigned int idx, 242e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 243e5027893SAdrian Hunter { 244e5027893SAdrian Hunter struct auxtrace_queue *queue; 245e5027893SAdrian Hunter int err; 246e5027893SAdrian Hunter 247e5027893SAdrian Hunter if (idx >= queues->nr_queues) { 248e5027893SAdrian Hunter err = auxtrace_queues__grow(queues, idx + 1); 249e5027893SAdrian Hunter if (err) 250e5027893SAdrian Hunter return err; 251e5027893SAdrian Hunter } 252e5027893SAdrian Hunter 253e5027893SAdrian Hunter queue = &queues->queue_array[idx]; 254e5027893SAdrian Hunter 255e5027893SAdrian Hunter if (!queue->set) { 256e5027893SAdrian Hunter queue->set = true; 257e5027893SAdrian Hunter queue->tid = buffer->tid; 258e5027893SAdrian Hunter queue->cpu = buffer->cpu; 259e5027893SAdrian Hunter } else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) { 260e5027893SAdrian Hunter pr_err("auxtrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n", 261e5027893SAdrian Hunter queue->cpu, queue->tid, buffer->cpu, buffer->tid); 262e5027893SAdrian Hunter return -EINVAL; 263e5027893SAdrian Hunter } 264e5027893SAdrian Hunter 265e5027893SAdrian Hunter buffer->buffer_nr = queues->next_buffer_nr++; 266e5027893SAdrian Hunter 267e5027893SAdrian Hunter list_add_tail(&buffer->list, &queue->head); 268e5027893SAdrian Hunter 269e5027893SAdrian Hunter queues->new_data = true; 270e5027893SAdrian Hunter queues->populated = true; 271e5027893SAdrian Hunter 272e5027893SAdrian Hunter return 0; 273e5027893SAdrian Hunter } 274e5027893SAdrian Hunter 275e5027893SAdrian Hunter /* Limit buffers to 32MiB on 32-bit */ 276e5027893SAdrian Hunter #define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024) 277e5027893SAdrian Hunter 278e5027893SAdrian Hunter static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues, 279e5027893SAdrian Hunter unsigned int idx, 280e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 281e5027893SAdrian Hunter { 282e5027893SAdrian Hunter u64 sz = buffer->size; 283e5027893SAdrian Hunter bool consecutive = false; 284e5027893SAdrian Hunter struct auxtrace_buffer *b; 285e5027893SAdrian Hunter int err; 286e5027893SAdrian Hunter 287e5027893SAdrian Hunter while (sz > BUFFER_LIMIT_FOR_32_BIT) { 288e5027893SAdrian Hunter b = memdup(buffer, sizeof(struct auxtrace_buffer)); 289e5027893SAdrian Hunter if (!b) 290e5027893SAdrian Hunter return -ENOMEM; 291e5027893SAdrian Hunter b->size = BUFFER_LIMIT_FOR_32_BIT; 292e5027893SAdrian Hunter b->consecutive = consecutive; 293a356a597SAdrian Hunter err = auxtrace_queues__queue_buffer(queues, idx, b); 294e5027893SAdrian Hunter if (err) { 295e5027893SAdrian Hunter auxtrace_buffer__free(b); 296e5027893SAdrian Hunter return err; 297e5027893SAdrian Hunter } 298e5027893SAdrian Hunter buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT; 299e5027893SAdrian Hunter sz -= BUFFER_LIMIT_FOR_32_BIT; 300e5027893SAdrian Hunter consecutive = true; 301e5027893SAdrian Hunter } 302e5027893SAdrian Hunter 303e5027893SAdrian Hunter buffer->size = sz; 304e5027893SAdrian Hunter buffer->consecutive = consecutive; 305e5027893SAdrian Hunter 306e5027893SAdrian Hunter return 0; 307e5027893SAdrian Hunter } 308e5027893SAdrian Hunter 309b238db65SAdrian Hunter static bool filter_cpu(struct perf_session *session, int cpu) 310b238db65SAdrian Hunter { 311b238db65SAdrian Hunter unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; 312b238db65SAdrian Hunter 313b238db65SAdrian Hunter return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); 314b238db65SAdrian Hunter } 315b238db65SAdrian Hunter 316a356a597SAdrian Hunter static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, 317e5027893SAdrian Hunter struct perf_session *session, 318e5027893SAdrian Hunter unsigned int idx, 3194c454843SAdrian Hunter struct auxtrace_buffer *buffer, 3204c454843SAdrian Hunter struct auxtrace_buffer **buffer_ptr) 321e5027893SAdrian Hunter { 3220d75f123SAdrian Hunter int err = -ENOMEM; 3230d75f123SAdrian Hunter 324b238db65SAdrian Hunter if (filter_cpu(session, buffer->cpu)) 325b238db65SAdrian Hunter return 0; 326b238db65SAdrian Hunter 3270d75f123SAdrian Hunter buffer = memdup(buffer, sizeof(*buffer)); 3280d75f123SAdrian Hunter if (!buffer) 3290d75f123SAdrian Hunter return -ENOMEM; 3304c454843SAdrian Hunter 331e5027893SAdrian Hunter if (session->one_mmap) { 332e5027893SAdrian Hunter buffer->data = buffer->data_offset - session->one_mmap_offset + 333e5027893SAdrian Hunter session->one_mmap_addr; 3348ceb41d7SJiri Olsa } else if (perf_data__is_pipe(session->data)) { 335e5027893SAdrian Hunter buffer->data = auxtrace_copy_data(buffer->size, session); 336e5027893SAdrian Hunter if (!buffer->data) 3370d75f123SAdrian Hunter goto out_free; 338e5027893SAdrian Hunter buffer->data_needs_freeing = true; 339e5027893SAdrian Hunter } else if (BITS_PER_LONG == 32 && 340e5027893SAdrian Hunter buffer->size > BUFFER_LIMIT_FOR_32_BIT) { 341e5027893SAdrian Hunter err = auxtrace_queues__split_buffer(queues, idx, buffer); 342e5027893SAdrian Hunter if (err) 3430d75f123SAdrian Hunter goto out_free; 344e5027893SAdrian Hunter } 345e5027893SAdrian Hunter 3464c454843SAdrian Hunter err = auxtrace_queues__queue_buffer(queues, idx, buffer); 3474c454843SAdrian Hunter if (err) 3480d75f123SAdrian Hunter goto out_free; 3494c454843SAdrian Hunter 3504c454843SAdrian Hunter /* FIXME: Doesn't work for split buffer */ 3514c454843SAdrian Hunter if (buffer_ptr) 3524c454843SAdrian Hunter *buffer_ptr = buffer; 3534c454843SAdrian Hunter 3544c454843SAdrian Hunter return 0; 3550d75f123SAdrian Hunter 3560d75f123SAdrian Hunter out_free: 3570d75f123SAdrian Hunter auxtrace_buffer__free(buffer); 3580d75f123SAdrian Hunter return err; 359e5027893SAdrian Hunter } 360e5027893SAdrian Hunter 361e5027893SAdrian Hunter int auxtrace_queues__add_event(struct auxtrace_queues *queues, 362e5027893SAdrian Hunter struct perf_session *session, 363e5027893SAdrian Hunter union perf_event *event, off_t data_offset, 364e5027893SAdrian Hunter struct auxtrace_buffer **buffer_ptr) 365e5027893SAdrian Hunter { 3660d75f123SAdrian Hunter struct auxtrace_buffer buffer = { 3670d75f123SAdrian Hunter .pid = -1, 3680d75f123SAdrian Hunter .tid = event->auxtrace.tid, 3690d75f123SAdrian Hunter .cpu = event->auxtrace.cpu, 3700d75f123SAdrian Hunter .data_offset = data_offset, 3710d75f123SAdrian Hunter .offset = event->auxtrace.offset, 3720d75f123SAdrian Hunter .reference = event->auxtrace.reference, 3730d75f123SAdrian Hunter .size = event->auxtrace.size, 3740d75f123SAdrian Hunter }; 3750d75f123SAdrian Hunter unsigned int idx = event->auxtrace.idx; 376e5027893SAdrian Hunter 3770d75f123SAdrian Hunter return auxtrace_queues__add_buffer(queues, session, idx, &buffer, 3784c454843SAdrian Hunter buffer_ptr); 379e5027893SAdrian Hunter } 380e5027893SAdrian Hunter 38199fa2984SAdrian Hunter static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, 38299fa2984SAdrian Hunter struct perf_session *session, 38399fa2984SAdrian Hunter off_t file_offset, size_t sz) 38499fa2984SAdrian Hunter { 38599fa2984SAdrian Hunter union perf_event *event; 38699fa2984SAdrian Hunter int err; 38799fa2984SAdrian Hunter char buf[PERF_SAMPLE_MAX_SIZE]; 38899fa2984SAdrian Hunter 38999fa2984SAdrian Hunter err = perf_session__peek_event(session, file_offset, buf, 39099fa2984SAdrian Hunter PERF_SAMPLE_MAX_SIZE, &event, NULL); 39199fa2984SAdrian Hunter if (err) 39299fa2984SAdrian Hunter return err; 39399fa2984SAdrian Hunter 39499fa2984SAdrian Hunter if (event->header.type == PERF_RECORD_AUXTRACE) { 39599fa2984SAdrian Hunter if (event->header.size < sizeof(struct auxtrace_event) || 39699fa2984SAdrian Hunter event->header.size != sz) { 39799fa2984SAdrian Hunter err = -EINVAL; 39899fa2984SAdrian Hunter goto out; 39999fa2984SAdrian Hunter } 40099fa2984SAdrian Hunter file_offset += event->header.size; 40199fa2984SAdrian Hunter err = auxtrace_queues__add_event(queues, session, event, 40299fa2984SAdrian Hunter file_offset, NULL); 40399fa2984SAdrian Hunter } 40499fa2984SAdrian Hunter out: 40599fa2984SAdrian Hunter return err; 40699fa2984SAdrian Hunter } 40799fa2984SAdrian Hunter 408e5027893SAdrian Hunter void auxtrace_queues__free(struct auxtrace_queues *queues) 409e5027893SAdrian Hunter { 410e5027893SAdrian Hunter unsigned int i; 411e5027893SAdrian Hunter 412e5027893SAdrian Hunter for (i = 0; i < queues->nr_queues; i++) { 413e5027893SAdrian Hunter while (!list_empty(&queues->queue_array[i].head)) { 414e5027893SAdrian Hunter struct auxtrace_buffer *buffer; 415e5027893SAdrian Hunter 416e5027893SAdrian Hunter buffer = list_entry(queues->queue_array[i].head.next, 417e5027893SAdrian Hunter struct auxtrace_buffer, list); 418e5027893SAdrian Hunter list_del(&buffer->list); 419e5027893SAdrian Hunter auxtrace_buffer__free(buffer); 420e5027893SAdrian Hunter } 421e5027893SAdrian Hunter } 422e5027893SAdrian Hunter 423e5027893SAdrian Hunter zfree(&queues->queue_array); 424e5027893SAdrian Hunter queues->nr_queues = 0; 425e5027893SAdrian Hunter } 426e5027893SAdrian Hunter 427f9397155SAdrian Hunter static void auxtrace_heapify(struct auxtrace_heap_item *heap_array, 428f9397155SAdrian Hunter unsigned int pos, unsigned int queue_nr, 429f9397155SAdrian Hunter u64 ordinal) 430f9397155SAdrian Hunter { 431f9397155SAdrian Hunter unsigned int parent; 432f9397155SAdrian Hunter 433f9397155SAdrian Hunter while (pos) { 434f9397155SAdrian Hunter parent = (pos - 1) >> 1; 435f9397155SAdrian Hunter if (heap_array[parent].ordinal <= ordinal) 436f9397155SAdrian Hunter break; 437f9397155SAdrian Hunter heap_array[pos] = heap_array[parent]; 438f9397155SAdrian Hunter pos = parent; 439f9397155SAdrian Hunter } 440f9397155SAdrian Hunter heap_array[pos].queue_nr = queue_nr; 441f9397155SAdrian Hunter heap_array[pos].ordinal = ordinal; 442f9397155SAdrian Hunter } 443f9397155SAdrian Hunter 444f9397155SAdrian Hunter int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr, 445f9397155SAdrian Hunter u64 ordinal) 446f9397155SAdrian Hunter { 447f9397155SAdrian Hunter struct auxtrace_heap_item *heap_array; 448f9397155SAdrian Hunter 449f9397155SAdrian Hunter if (queue_nr >= heap->heap_sz) { 450f9397155SAdrian Hunter unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES; 451f9397155SAdrian Hunter 452f9397155SAdrian Hunter while (heap_sz <= queue_nr) 453f9397155SAdrian Hunter heap_sz <<= 1; 454f9397155SAdrian Hunter heap_array = realloc(heap->heap_array, 455f9397155SAdrian Hunter heap_sz * sizeof(struct auxtrace_heap_item)); 456f9397155SAdrian Hunter if (!heap_array) 457f9397155SAdrian Hunter return -ENOMEM; 458f9397155SAdrian Hunter heap->heap_array = heap_array; 459f9397155SAdrian Hunter heap->heap_sz = heap_sz; 460f9397155SAdrian Hunter } 461f9397155SAdrian Hunter 462f9397155SAdrian Hunter auxtrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal); 463f9397155SAdrian Hunter 464f9397155SAdrian Hunter return 0; 465f9397155SAdrian Hunter } 466f9397155SAdrian Hunter 467f9397155SAdrian Hunter void auxtrace_heap__free(struct auxtrace_heap *heap) 468f9397155SAdrian Hunter { 469f9397155SAdrian Hunter zfree(&heap->heap_array); 470f9397155SAdrian Hunter heap->heap_cnt = 0; 471f9397155SAdrian Hunter heap->heap_sz = 0; 472f9397155SAdrian Hunter } 473f9397155SAdrian Hunter 474f9397155SAdrian Hunter void auxtrace_heap__pop(struct auxtrace_heap *heap) 475f9397155SAdrian Hunter { 476f9397155SAdrian Hunter unsigned int pos, last, heap_cnt = heap->heap_cnt; 477f9397155SAdrian Hunter struct auxtrace_heap_item *heap_array; 478f9397155SAdrian Hunter 479f9397155SAdrian Hunter if (!heap_cnt) 480f9397155SAdrian Hunter return; 481f9397155SAdrian Hunter 482f9397155SAdrian Hunter heap->heap_cnt -= 1; 483f9397155SAdrian Hunter 484f9397155SAdrian Hunter heap_array = heap->heap_array; 485f9397155SAdrian Hunter 486f9397155SAdrian Hunter pos = 0; 487f9397155SAdrian Hunter while (1) { 488f9397155SAdrian Hunter unsigned int left, right; 489f9397155SAdrian Hunter 490f9397155SAdrian Hunter left = (pos << 1) + 1; 491f9397155SAdrian Hunter if (left >= heap_cnt) 492f9397155SAdrian Hunter break; 493f9397155SAdrian Hunter right = left + 1; 494f9397155SAdrian Hunter if (right >= heap_cnt) { 495f9397155SAdrian Hunter heap_array[pos] = heap_array[left]; 496f9397155SAdrian Hunter return; 497f9397155SAdrian Hunter } 498f9397155SAdrian Hunter if (heap_array[left].ordinal < heap_array[right].ordinal) { 499f9397155SAdrian Hunter heap_array[pos] = heap_array[left]; 500f9397155SAdrian Hunter pos = left; 501f9397155SAdrian Hunter } else { 502f9397155SAdrian Hunter heap_array[pos] = heap_array[right]; 503f9397155SAdrian Hunter pos = right; 504f9397155SAdrian Hunter } 505f9397155SAdrian Hunter } 506f9397155SAdrian Hunter 507f9397155SAdrian Hunter last = heap_cnt - 1; 508f9397155SAdrian Hunter auxtrace_heapify(heap_array, pos, heap_array[last].queue_nr, 509f9397155SAdrian Hunter heap_array[last].ordinal); 510f9397155SAdrian Hunter } 511f9397155SAdrian Hunter 51214a05e13SMathieu Poirier size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, 51314a05e13SMathieu Poirier struct perf_evlist *evlist) 5149e0cc4feSAdrian Hunter { 5159e0cc4feSAdrian Hunter if (itr) 51614a05e13SMathieu Poirier return itr->info_priv_size(itr, evlist); 5179e0cc4feSAdrian Hunter return 0; 5189e0cc4feSAdrian Hunter } 5199e0cc4feSAdrian Hunter 5209e0cc4feSAdrian Hunter static int auxtrace_not_supported(void) 5219e0cc4feSAdrian Hunter { 5229e0cc4feSAdrian Hunter pr_err("AUX area tracing is not supported on this architecture\n"); 5239e0cc4feSAdrian Hunter return -EINVAL; 5249e0cc4feSAdrian Hunter } 5259e0cc4feSAdrian Hunter 5269e0cc4feSAdrian Hunter int auxtrace_record__info_fill(struct auxtrace_record *itr, 5279e0cc4feSAdrian Hunter struct perf_session *session, 5289e0cc4feSAdrian Hunter struct auxtrace_info_event *auxtrace_info, 5299e0cc4feSAdrian Hunter size_t priv_size) 5309e0cc4feSAdrian Hunter { 5319e0cc4feSAdrian Hunter if (itr) 5329e0cc4feSAdrian Hunter return itr->info_fill(itr, session, auxtrace_info, priv_size); 5339e0cc4feSAdrian Hunter return auxtrace_not_supported(); 5349e0cc4feSAdrian Hunter } 5359e0cc4feSAdrian Hunter 5369e0cc4feSAdrian Hunter void auxtrace_record__free(struct auxtrace_record *itr) 5379e0cc4feSAdrian Hunter { 5389e0cc4feSAdrian Hunter if (itr) 5399e0cc4feSAdrian Hunter itr->free(itr); 5409e0cc4feSAdrian Hunter } 5419e0cc4feSAdrian Hunter 542d20031bbSAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr) 543d20031bbSAdrian Hunter { 544d20031bbSAdrian Hunter if (itr && itr->snapshot_start) 545d20031bbSAdrian Hunter return itr->snapshot_start(itr); 546d20031bbSAdrian Hunter return 0; 547d20031bbSAdrian Hunter } 548d20031bbSAdrian Hunter 549d20031bbSAdrian Hunter int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) 550d20031bbSAdrian Hunter { 551d20031bbSAdrian Hunter if (itr && itr->snapshot_finish) 552d20031bbSAdrian Hunter return itr->snapshot_finish(itr); 553d20031bbSAdrian Hunter return 0; 554d20031bbSAdrian Hunter } 555d20031bbSAdrian Hunter 556d20031bbSAdrian Hunter int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, 557d20031bbSAdrian Hunter struct auxtrace_mmap *mm, 558d20031bbSAdrian Hunter unsigned char *data, u64 *head, u64 *old) 559d20031bbSAdrian Hunter { 560d20031bbSAdrian Hunter if (itr && itr->find_snapshot) 561d20031bbSAdrian Hunter return itr->find_snapshot(itr, idx, mm, data, head, old); 562d20031bbSAdrian Hunter return 0; 563d20031bbSAdrian Hunter } 564d20031bbSAdrian Hunter 5659e0cc4feSAdrian Hunter int auxtrace_record__options(struct auxtrace_record *itr, 5669e0cc4feSAdrian Hunter struct perf_evlist *evlist, 5679e0cc4feSAdrian Hunter struct record_opts *opts) 5689e0cc4feSAdrian Hunter { 5699e0cc4feSAdrian Hunter if (itr) 5709e0cc4feSAdrian Hunter return itr->recording_options(itr, evlist, opts); 5719e0cc4feSAdrian Hunter return 0; 5729e0cc4feSAdrian Hunter } 5739e0cc4feSAdrian Hunter 5749e0cc4feSAdrian Hunter u64 auxtrace_record__reference(struct auxtrace_record *itr) 5759e0cc4feSAdrian Hunter { 5769e0cc4feSAdrian Hunter if (itr) 5779e0cc4feSAdrian Hunter return itr->reference(itr); 5789e0cc4feSAdrian Hunter return 0; 5799e0cc4feSAdrian Hunter } 5809e0cc4feSAdrian Hunter 581d20031bbSAdrian Hunter int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, 582d20031bbSAdrian Hunter struct record_opts *opts, const char *str) 583d20031bbSAdrian Hunter { 584d20031bbSAdrian Hunter if (!str) 585d20031bbSAdrian Hunter return 0; 586d20031bbSAdrian Hunter 587d20031bbSAdrian Hunter if (itr) 588d20031bbSAdrian Hunter return itr->parse_snapshot_options(itr, opts, str); 589d20031bbSAdrian Hunter 590d20031bbSAdrian Hunter pr_err("No AUX area tracing to snapshot\n"); 591d20031bbSAdrian Hunter return -EINVAL; 592d20031bbSAdrian Hunter } 593d20031bbSAdrian Hunter 5949e0cc4feSAdrian Hunter struct auxtrace_record *__weak 5959e0cc4feSAdrian Hunter auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) 5969e0cc4feSAdrian Hunter { 5979e0cc4feSAdrian Hunter *err = 0; 5989e0cc4feSAdrian Hunter return NULL; 5999e0cc4feSAdrian Hunter } 6009e0cc4feSAdrian Hunter 60199fa2984SAdrian Hunter static int auxtrace_index__alloc(struct list_head *head) 60299fa2984SAdrian Hunter { 60399fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 60499fa2984SAdrian Hunter 60599fa2984SAdrian Hunter auxtrace_index = malloc(sizeof(struct auxtrace_index)); 60699fa2984SAdrian Hunter if (!auxtrace_index) 60799fa2984SAdrian Hunter return -ENOMEM; 60899fa2984SAdrian Hunter 60999fa2984SAdrian Hunter auxtrace_index->nr = 0; 61099fa2984SAdrian Hunter INIT_LIST_HEAD(&auxtrace_index->list); 61199fa2984SAdrian Hunter 61299fa2984SAdrian Hunter list_add_tail(&auxtrace_index->list, head); 61399fa2984SAdrian Hunter 61499fa2984SAdrian Hunter return 0; 61599fa2984SAdrian Hunter } 61699fa2984SAdrian Hunter 61799fa2984SAdrian Hunter void auxtrace_index__free(struct list_head *head) 61899fa2984SAdrian Hunter { 61999fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index, *n; 62099fa2984SAdrian Hunter 62199fa2984SAdrian Hunter list_for_each_entry_safe(auxtrace_index, n, head, list) { 62299fa2984SAdrian Hunter list_del(&auxtrace_index->list); 62399fa2984SAdrian Hunter free(auxtrace_index); 62499fa2984SAdrian Hunter } 62599fa2984SAdrian Hunter } 62699fa2984SAdrian Hunter 62799fa2984SAdrian Hunter static struct auxtrace_index *auxtrace_index__last(struct list_head *head) 62899fa2984SAdrian Hunter { 62999fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 63099fa2984SAdrian Hunter int err; 63199fa2984SAdrian Hunter 63299fa2984SAdrian Hunter if (list_empty(head)) { 63399fa2984SAdrian Hunter err = auxtrace_index__alloc(head); 63499fa2984SAdrian Hunter if (err) 63599fa2984SAdrian Hunter return NULL; 63699fa2984SAdrian Hunter } 63799fa2984SAdrian Hunter 63899fa2984SAdrian Hunter auxtrace_index = list_entry(head->prev, struct auxtrace_index, list); 63999fa2984SAdrian Hunter 64099fa2984SAdrian Hunter if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) { 64199fa2984SAdrian Hunter err = auxtrace_index__alloc(head); 64299fa2984SAdrian Hunter if (err) 64399fa2984SAdrian Hunter return NULL; 64499fa2984SAdrian Hunter auxtrace_index = list_entry(head->prev, struct auxtrace_index, 64599fa2984SAdrian Hunter list); 64699fa2984SAdrian Hunter } 64799fa2984SAdrian Hunter 64899fa2984SAdrian Hunter return auxtrace_index; 64999fa2984SAdrian Hunter } 65099fa2984SAdrian Hunter 65199fa2984SAdrian Hunter int auxtrace_index__auxtrace_event(struct list_head *head, 65299fa2984SAdrian Hunter union perf_event *event, off_t file_offset) 65399fa2984SAdrian Hunter { 65499fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 65599fa2984SAdrian Hunter size_t nr; 65699fa2984SAdrian Hunter 65799fa2984SAdrian Hunter auxtrace_index = auxtrace_index__last(head); 65899fa2984SAdrian Hunter if (!auxtrace_index) 65999fa2984SAdrian Hunter return -ENOMEM; 66099fa2984SAdrian Hunter 66199fa2984SAdrian Hunter nr = auxtrace_index->nr; 66299fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = file_offset; 66399fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = event->header.size; 66499fa2984SAdrian Hunter auxtrace_index->nr += 1; 66599fa2984SAdrian Hunter 66699fa2984SAdrian Hunter return 0; 66799fa2984SAdrian Hunter } 66899fa2984SAdrian Hunter 66999fa2984SAdrian Hunter static int auxtrace_index__do_write(int fd, 67099fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index) 67199fa2984SAdrian Hunter { 67299fa2984SAdrian Hunter struct auxtrace_index_entry ent; 67399fa2984SAdrian Hunter size_t i; 67499fa2984SAdrian Hunter 67599fa2984SAdrian Hunter for (i = 0; i < auxtrace_index->nr; i++) { 67699fa2984SAdrian Hunter ent.file_offset = auxtrace_index->entries[i].file_offset; 67799fa2984SAdrian Hunter ent.sz = auxtrace_index->entries[i].sz; 67899fa2984SAdrian Hunter if (writen(fd, &ent, sizeof(ent)) != sizeof(ent)) 67999fa2984SAdrian Hunter return -errno; 68099fa2984SAdrian Hunter } 68199fa2984SAdrian Hunter return 0; 68299fa2984SAdrian Hunter } 68399fa2984SAdrian Hunter 68499fa2984SAdrian Hunter int auxtrace_index__write(int fd, struct list_head *head) 68599fa2984SAdrian Hunter { 68699fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 68799fa2984SAdrian Hunter u64 total = 0; 68899fa2984SAdrian Hunter int err; 68999fa2984SAdrian Hunter 69099fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, head, list) 69199fa2984SAdrian Hunter total += auxtrace_index->nr; 69299fa2984SAdrian Hunter 69399fa2984SAdrian Hunter if (writen(fd, &total, sizeof(total)) != sizeof(total)) 69499fa2984SAdrian Hunter return -errno; 69599fa2984SAdrian Hunter 69699fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, head, list) { 69799fa2984SAdrian Hunter err = auxtrace_index__do_write(fd, auxtrace_index); 69899fa2984SAdrian Hunter if (err) 69999fa2984SAdrian Hunter return err; 70099fa2984SAdrian Hunter } 70199fa2984SAdrian Hunter 70299fa2984SAdrian Hunter return 0; 70399fa2984SAdrian Hunter } 70499fa2984SAdrian Hunter 70599fa2984SAdrian Hunter static int auxtrace_index__process_entry(int fd, struct list_head *head, 70699fa2984SAdrian Hunter bool needs_swap) 70799fa2984SAdrian Hunter { 70899fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 70999fa2984SAdrian Hunter struct auxtrace_index_entry ent; 71099fa2984SAdrian Hunter size_t nr; 71199fa2984SAdrian Hunter 71299fa2984SAdrian Hunter if (readn(fd, &ent, sizeof(ent)) != sizeof(ent)) 71399fa2984SAdrian Hunter return -1; 71499fa2984SAdrian Hunter 71599fa2984SAdrian Hunter auxtrace_index = auxtrace_index__last(head); 71699fa2984SAdrian Hunter if (!auxtrace_index) 71799fa2984SAdrian Hunter return -1; 71899fa2984SAdrian Hunter 71999fa2984SAdrian Hunter nr = auxtrace_index->nr; 72099fa2984SAdrian Hunter if (needs_swap) { 72199fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = 72299fa2984SAdrian Hunter bswap_64(ent.file_offset); 72399fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = bswap_64(ent.sz); 72499fa2984SAdrian Hunter } else { 72599fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = ent.file_offset; 72699fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = ent.sz; 72799fa2984SAdrian Hunter } 72899fa2984SAdrian Hunter 72999fa2984SAdrian Hunter auxtrace_index->nr = nr + 1; 73099fa2984SAdrian Hunter 73199fa2984SAdrian Hunter return 0; 73299fa2984SAdrian Hunter } 73399fa2984SAdrian Hunter 73499fa2984SAdrian Hunter int auxtrace_index__process(int fd, u64 size, struct perf_session *session, 73599fa2984SAdrian Hunter bool needs_swap) 73699fa2984SAdrian Hunter { 73799fa2984SAdrian Hunter struct list_head *head = &session->auxtrace_index; 73899fa2984SAdrian Hunter u64 nr; 73999fa2984SAdrian Hunter 74099fa2984SAdrian Hunter if (readn(fd, &nr, sizeof(u64)) != sizeof(u64)) 74199fa2984SAdrian Hunter return -1; 74299fa2984SAdrian Hunter 74399fa2984SAdrian Hunter if (needs_swap) 74499fa2984SAdrian Hunter nr = bswap_64(nr); 74599fa2984SAdrian Hunter 74699fa2984SAdrian Hunter if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size) 74799fa2984SAdrian Hunter return -1; 74899fa2984SAdrian Hunter 74999fa2984SAdrian Hunter while (nr--) { 75099fa2984SAdrian Hunter int err; 75199fa2984SAdrian Hunter 75299fa2984SAdrian Hunter err = auxtrace_index__process_entry(fd, head, needs_swap); 75399fa2984SAdrian Hunter if (err) 75499fa2984SAdrian Hunter return -1; 75599fa2984SAdrian Hunter } 75699fa2984SAdrian Hunter 75799fa2984SAdrian Hunter return 0; 75899fa2984SAdrian Hunter } 75999fa2984SAdrian Hunter 76099fa2984SAdrian Hunter static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues, 76199fa2984SAdrian Hunter struct perf_session *session, 76299fa2984SAdrian Hunter struct auxtrace_index_entry *ent) 76399fa2984SAdrian Hunter { 76499fa2984SAdrian Hunter return auxtrace_queues__add_indexed_event(queues, session, 76599fa2984SAdrian Hunter ent->file_offset, ent->sz); 76699fa2984SAdrian Hunter } 76799fa2984SAdrian Hunter 76899fa2984SAdrian Hunter int auxtrace_queues__process_index(struct auxtrace_queues *queues, 76999fa2984SAdrian Hunter struct perf_session *session) 77099fa2984SAdrian Hunter { 77199fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 77299fa2984SAdrian Hunter struct auxtrace_index_entry *ent; 77399fa2984SAdrian Hunter size_t i; 77499fa2984SAdrian Hunter int err; 77599fa2984SAdrian Hunter 7762e2967f4SAdrian Hunter if (auxtrace__dont_decode(session)) 7772e2967f4SAdrian Hunter return 0; 7782e2967f4SAdrian Hunter 77999fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { 78099fa2984SAdrian Hunter for (i = 0; i < auxtrace_index->nr; i++) { 78199fa2984SAdrian Hunter ent = &auxtrace_index->entries[i]; 78299fa2984SAdrian Hunter err = auxtrace_queues__process_index_entry(queues, 78399fa2984SAdrian Hunter session, 78499fa2984SAdrian Hunter ent); 78599fa2984SAdrian Hunter if (err) 78699fa2984SAdrian Hunter return err; 78799fa2984SAdrian Hunter } 78899fa2984SAdrian Hunter } 78999fa2984SAdrian Hunter return 0; 79099fa2984SAdrian Hunter } 79199fa2984SAdrian Hunter 792e5027893SAdrian Hunter struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, 793e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 794e5027893SAdrian Hunter { 795e5027893SAdrian Hunter if (buffer) { 796e5027893SAdrian Hunter if (list_is_last(&buffer->list, &queue->head)) 797e5027893SAdrian Hunter return NULL; 798e5027893SAdrian Hunter return list_entry(buffer->list.next, struct auxtrace_buffer, 799e5027893SAdrian Hunter list); 800e5027893SAdrian Hunter } else { 801e5027893SAdrian Hunter if (list_empty(&queue->head)) 802e5027893SAdrian Hunter return NULL; 803e5027893SAdrian Hunter return list_entry(queue->head.next, struct auxtrace_buffer, 804e5027893SAdrian Hunter list); 805e5027893SAdrian Hunter } 806e5027893SAdrian Hunter } 807e5027893SAdrian Hunter 808e5027893SAdrian Hunter void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd) 809e5027893SAdrian Hunter { 810e5027893SAdrian Hunter size_t adj = buffer->data_offset & (page_size - 1); 811e5027893SAdrian Hunter size_t size = buffer->size + adj; 812e5027893SAdrian Hunter off_t file_offset = buffer->data_offset - adj; 813e5027893SAdrian Hunter void *addr; 814e5027893SAdrian Hunter 815e5027893SAdrian Hunter if (buffer->data) 816e5027893SAdrian Hunter return buffer->data; 817e5027893SAdrian Hunter 818e5027893SAdrian Hunter addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset); 819e5027893SAdrian Hunter if (addr == MAP_FAILED) 820e5027893SAdrian Hunter return NULL; 821e5027893SAdrian Hunter 822e5027893SAdrian Hunter buffer->mmap_addr = addr; 823e5027893SAdrian Hunter buffer->mmap_size = size; 824e5027893SAdrian Hunter 825e5027893SAdrian Hunter buffer->data = addr + adj; 826e5027893SAdrian Hunter 827e5027893SAdrian Hunter return buffer->data; 828e5027893SAdrian Hunter } 829e5027893SAdrian Hunter 830e5027893SAdrian Hunter void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer) 831e5027893SAdrian Hunter { 832e5027893SAdrian Hunter if (!buffer->data || !buffer->mmap_addr) 833e5027893SAdrian Hunter return; 834e5027893SAdrian Hunter munmap(buffer->mmap_addr, buffer->mmap_size); 835e5027893SAdrian Hunter buffer->mmap_addr = NULL; 836e5027893SAdrian Hunter buffer->mmap_size = 0; 837e5027893SAdrian Hunter buffer->data = NULL; 838e5027893SAdrian Hunter buffer->use_data = NULL; 839e5027893SAdrian Hunter } 840e5027893SAdrian Hunter 841e5027893SAdrian Hunter void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer) 842e5027893SAdrian Hunter { 843e5027893SAdrian Hunter auxtrace_buffer__put_data(buffer); 844e5027893SAdrian Hunter if (buffer->data_needs_freeing) { 845e5027893SAdrian Hunter buffer->data_needs_freeing = false; 846e5027893SAdrian Hunter zfree(&buffer->data); 847e5027893SAdrian Hunter buffer->use_data = NULL; 848e5027893SAdrian Hunter buffer->size = 0; 849e5027893SAdrian Hunter } 850e5027893SAdrian Hunter } 851e5027893SAdrian Hunter 852e5027893SAdrian Hunter void auxtrace_buffer__free(struct auxtrace_buffer *buffer) 853e5027893SAdrian Hunter { 854e5027893SAdrian Hunter auxtrace_buffer__drop_data(buffer); 855e5027893SAdrian Hunter free(buffer); 856e5027893SAdrian Hunter } 857e5027893SAdrian Hunter 85885ed4729SAdrian Hunter void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, 85985ed4729SAdrian Hunter int code, int cpu, pid_t pid, pid_t tid, u64 ip, 86085ed4729SAdrian Hunter const char *msg) 86185ed4729SAdrian Hunter { 86285ed4729SAdrian Hunter size_t size; 86385ed4729SAdrian Hunter 86485ed4729SAdrian Hunter memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event)); 86585ed4729SAdrian Hunter 86685ed4729SAdrian Hunter auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; 86785ed4729SAdrian Hunter auxtrace_error->type = type; 86885ed4729SAdrian Hunter auxtrace_error->code = code; 86985ed4729SAdrian Hunter auxtrace_error->cpu = cpu; 87085ed4729SAdrian Hunter auxtrace_error->pid = pid; 87185ed4729SAdrian Hunter auxtrace_error->tid = tid; 87285ed4729SAdrian Hunter auxtrace_error->ip = ip; 87385ed4729SAdrian Hunter strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG); 87485ed4729SAdrian Hunter 87585ed4729SAdrian Hunter size = (void *)auxtrace_error->msg - (void *)auxtrace_error + 87685ed4729SAdrian Hunter strlen(auxtrace_error->msg) + 1; 87785ed4729SAdrian Hunter auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64)); 87885ed4729SAdrian Hunter } 87985ed4729SAdrian Hunter 8809e0cc4feSAdrian Hunter int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, 8819e0cc4feSAdrian Hunter struct perf_tool *tool, 8829e0cc4feSAdrian Hunter struct perf_session *session, 8839e0cc4feSAdrian Hunter perf_event__handler_t process) 8849e0cc4feSAdrian Hunter { 8859e0cc4feSAdrian Hunter union perf_event *ev; 8869e0cc4feSAdrian Hunter size_t priv_size; 8879e0cc4feSAdrian Hunter int err; 8889e0cc4feSAdrian Hunter 8899e0cc4feSAdrian Hunter pr_debug2("Synthesizing auxtrace information\n"); 89014a05e13SMathieu Poirier priv_size = auxtrace_record__info_priv_size(itr, session->evlist); 8919e0cc4feSAdrian Hunter ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); 8929e0cc4feSAdrian Hunter if (!ev) 8939e0cc4feSAdrian Hunter return -ENOMEM; 8949e0cc4feSAdrian Hunter 8959e0cc4feSAdrian Hunter ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO; 8969e0cc4feSAdrian Hunter ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) + 8979e0cc4feSAdrian Hunter priv_size; 8989e0cc4feSAdrian Hunter err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info, 8999e0cc4feSAdrian Hunter priv_size); 9009e0cc4feSAdrian Hunter if (err) 9019e0cc4feSAdrian Hunter goto out_free; 9029e0cc4feSAdrian Hunter 9039e0cc4feSAdrian Hunter err = process(tool, ev, NULL, NULL); 9049e0cc4feSAdrian Hunter out_free: 9059e0cc4feSAdrian Hunter free(ev); 9069e0cc4feSAdrian Hunter return err; 9079e0cc4feSAdrian Hunter } 9089e0cc4feSAdrian Hunter 909*89f1688aSJiri Olsa int perf_event__process_auxtrace_info(struct perf_session *session, 910*89f1688aSJiri Olsa union perf_event *event) 91173f75fb1SAdrian Hunter { 91273f75fb1SAdrian Hunter enum auxtrace_type type = event->auxtrace_info.type; 91373f75fb1SAdrian Hunter 91473f75fb1SAdrian Hunter if (dump_trace) 91573f75fb1SAdrian Hunter fprintf(stdout, " type: %u\n", type); 91673f75fb1SAdrian Hunter 91773f75fb1SAdrian Hunter switch (type) { 91855ea4ab4SAdrian Hunter case PERF_AUXTRACE_INTEL_PT: 9195efb1d54SAdrian Hunter return intel_pt_process_auxtrace_info(event, session); 920d0170af7SAdrian Hunter case PERF_AUXTRACE_INTEL_BTS: 921d0170af7SAdrian Hunter return intel_bts_process_auxtrace_info(event, session); 922ffd3d18cSKim Phillips case PERF_AUXTRACE_ARM_SPE: 923ffd3d18cSKim Phillips return arm_spe_process_auxtrace_info(event, session); 924a818c563SMathieu Poirier case PERF_AUXTRACE_CS_ETM: 925440a23b3SMathieu Poirier return cs_etm__process_auxtrace_info(event, session); 926b96e6615SThomas Richter case PERF_AUXTRACE_S390_CPUMSF: 927b96e6615SThomas Richter return s390_cpumsf_process_auxtrace_info(event, session); 92873f75fb1SAdrian Hunter case PERF_AUXTRACE_UNKNOWN: 92973f75fb1SAdrian Hunter default: 93073f75fb1SAdrian Hunter return -EINVAL; 93173f75fb1SAdrian Hunter } 93273f75fb1SAdrian Hunter } 93373f75fb1SAdrian Hunter 93473f75fb1SAdrian Hunter s64 perf_event__process_auxtrace(struct perf_tool *tool, 93573f75fb1SAdrian Hunter union perf_event *event, 93673f75fb1SAdrian Hunter struct perf_session *session) 93773f75fb1SAdrian Hunter { 93873f75fb1SAdrian Hunter s64 err; 93973f75fb1SAdrian Hunter 94073f75fb1SAdrian Hunter if (dump_trace) 94173f75fb1SAdrian Hunter fprintf(stdout, " size: %#"PRIx64" offset: %#"PRIx64" ref: %#"PRIx64" idx: %u tid: %d cpu: %d\n", 94273f75fb1SAdrian Hunter event->auxtrace.size, event->auxtrace.offset, 94373f75fb1SAdrian Hunter event->auxtrace.reference, event->auxtrace.idx, 94473f75fb1SAdrian Hunter event->auxtrace.tid, event->auxtrace.cpu); 94573f75fb1SAdrian Hunter 94673f75fb1SAdrian Hunter if (auxtrace__dont_decode(session)) 94773f75fb1SAdrian Hunter return event->auxtrace.size; 94873f75fb1SAdrian Hunter 94973f75fb1SAdrian Hunter if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE) 95073f75fb1SAdrian Hunter return -EINVAL; 95173f75fb1SAdrian Hunter 95273f75fb1SAdrian Hunter err = session->auxtrace->process_auxtrace_event(session, event, tool); 95373f75fb1SAdrian Hunter if (err < 0) 95473f75fb1SAdrian Hunter return err; 95573f75fb1SAdrian Hunter 95673f75fb1SAdrian Hunter return event->auxtrace.size; 95773f75fb1SAdrian Hunter } 95873f75fb1SAdrian Hunter 959f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS 960f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD 100000 961f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 962f6986c95SAdrian Hunter #define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 963601897b5SAdrian Hunter #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 964601897b5SAdrian Hunter #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 965f6986c95SAdrian Hunter 966f6986c95SAdrian Hunter void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) 967f6986c95SAdrian Hunter { 968f6986c95SAdrian Hunter synth_opts->instructions = true; 969f6986c95SAdrian Hunter synth_opts->branches = true; 97053c76b0eSAdrian Hunter synth_opts->transactions = true; 9713bdafdffSAdrian Hunter synth_opts->ptwrites = true; 97270d110d7SAdrian Hunter synth_opts->pwr_events = true; 973f6986c95SAdrian Hunter synth_opts->errors = true; 974f6986c95SAdrian Hunter synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; 975f6986c95SAdrian Hunter synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 976f6986c95SAdrian Hunter synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 977601897b5SAdrian Hunter synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 978d1706b39SAndi Kleen synth_opts->initial_skip = 0; 979f6986c95SAdrian Hunter } 980f6986c95SAdrian Hunter 981f6986c95SAdrian Hunter /* 982f6986c95SAdrian Hunter * Please check tools/perf/Documentation/perf-script.txt for information 983f6986c95SAdrian Hunter * about the options parsed here, which is introduced after this cset, 984f6986c95SAdrian Hunter * when support in 'perf script' for these options is introduced. 985f6986c95SAdrian Hunter */ 986f6986c95SAdrian Hunter int itrace_parse_synth_opts(const struct option *opt, const char *str, 987f6986c95SAdrian Hunter int unset) 988f6986c95SAdrian Hunter { 989f6986c95SAdrian Hunter struct itrace_synth_opts *synth_opts = opt->value; 990f6986c95SAdrian Hunter const char *p; 991f6986c95SAdrian Hunter char *endptr; 992f70cfa07SAdrian Hunter bool period_type_set = false; 993e1791347SAdrian Hunter bool period_set = false; 994f6986c95SAdrian Hunter 995f6986c95SAdrian Hunter synth_opts->set = true; 996f6986c95SAdrian Hunter 997f6986c95SAdrian Hunter if (unset) { 998f6986c95SAdrian Hunter synth_opts->dont_decode = true; 999f6986c95SAdrian Hunter return 0; 1000f6986c95SAdrian Hunter } 1001f6986c95SAdrian Hunter 1002f6986c95SAdrian Hunter if (!str) { 1003f6986c95SAdrian Hunter itrace_synth_opts__set_default(synth_opts); 1004f6986c95SAdrian Hunter return 0; 1005f6986c95SAdrian Hunter } 1006f6986c95SAdrian Hunter 1007f6986c95SAdrian Hunter for (p = str; *p;) { 1008f6986c95SAdrian Hunter switch (*p++) { 1009f6986c95SAdrian Hunter case 'i': 1010f6986c95SAdrian Hunter synth_opts->instructions = true; 1011f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1012f6986c95SAdrian Hunter p += 1; 1013f6986c95SAdrian Hunter if (isdigit(*p)) { 1014f6986c95SAdrian Hunter synth_opts->period = strtoull(p, &endptr, 10); 1015e1791347SAdrian Hunter period_set = true; 1016f6986c95SAdrian Hunter p = endptr; 1017f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1018f6986c95SAdrian Hunter p += 1; 1019f6986c95SAdrian Hunter switch (*p++) { 1020f6986c95SAdrian Hunter case 'i': 1021f6986c95SAdrian Hunter synth_opts->period_type = 1022f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_INSTRUCTIONS; 1023f70cfa07SAdrian Hunter period_type_set = true; 1024f6986c95SAdrian Hunter break; 1025f6986c95SAdrian Hunter case 't': 1026f6986c95SAdrian Hunter synth_opts->period_type = 1027f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_TICKS; 1028f70cfa07SAdrian Hunter period_type_set = true; 1029f6986c95SAdrian Hunter break; 1030f6986c95SAdrian Hunter case 'm': 1031f6986c95SAdrian Hunter synth_opts->period *= 1000; 1032f6986c95SAdrian Hunter /* Fall through */ 1033f6986c95SAdrian Hunter case 'u': 1034f6986c95SAdrian Hunter synth_opts->period *= 1000; 1035f6986c95SAdrian Hunter /* Fall through */ 1036f6986c95SAdrian Hunter case 'n': 1037f6986c95SAdrian Hunter if (*p++ != 's') 1038f6986c95SAdrian Hunter goto out_err; 1039f6986c95SAdrian Hunter synth_opts->period_type = 1040f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_NANOSECS; 1041f70cfa07SAdrian Hunter period_type_set = true; 1042f6986c95SAdrian Hunter break; 1043f6986c95SAdrian Hunter case '\0': 1044f6986c95SAdrian Hunter goto out; 1045f6986c95SAdrian Hunter default: 1046f6986c95SAdrian Hunter goto out_err; 1047f6986c95SAdrian Hunter } 1048f6986c95SAdrian Hunter } 1049f6986c95SAdrian Hunter break; 1050f6986c95SAdrian Hunter case 'b': 1051f6986c95SAdrian Hunter synth_opts->branches = true; 1052f6986c95SAdrian Hunter break; 105353c76b0eSAdrian Hunter case 'x': 105453c76b0eSAdrian Hunter synth_opts->transactions = true; 105553c76b0eSAdrian Hunter break; 10563bdafdffSAdrian Hunter case 'w': 10573bdafdffSAdrian Hunter synth_opts->ptwrites = true; 10583bdafdffSAdrian Hunter break; 105970d110d7SAdrian Hunter case 'p': 106070d110d7SAdrian Hunter synth_opts->pwr_events = true; 106170d110d7SAdrian Hunter break; 1062f6986c95SAdrian Hunter case 'e': 1063f6986c95SAdrian Hunter synth_opts->errors = true; 1064f6986c95SAdrian Hunter break; 1065f6986c95SAdrian Hunter case 'd': 1066f6986c95SAdrian Hunter synth_opts->log = true; 1067f6986c95SAdrian Hunter break; 1068f6986c95SAdrian Hunter case 'c': 1069f6986c95SAdrian Hunter synth_opts->branches = true; 1070f6986c95SAdrian Hunter synth_opts->calls = true; 1071f6986c95SAdrian Hunter break; 1072f6986c95SAdrian Hunter case 'r': 1073f6986c95SAdrian Hunter synth_opts->branches = true; 1074f6986c95SAdrian Hunter synth_opts->returns = true; 1075f6986c95SAdrian Hunter break; 1076f6986c95SAdrian Hunter case 'g': 1077f6986c95SAdrian Hunter synth_opts->callchain = true; 1078f6986c95SAdrian Hunter synth_opts->callchain_sz = 1079f6986c95SAdrian Hunter PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 1080f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1081f6986c95SAdrian Hunter p += 1; 1082f6986c95SAdrian Hunter if (isdigit(*p)) { 1083f6986c95SAdrian Hunter unsigned int val; 1084f6986c95SAdrian Hunter 1085f6986c95SAdrian Hunter val = strtoul(p, &endptr, 10); 1086f6986c95SAdrian Hunter p = endptr; 1087f6986c95SAdrian Hunter if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ) 1088f6986c95SAdrian Hunter goto out_err; 1089f6986c95SAdrian Hunter synth_opts->callchain_sz = val; 1090f6986c95SAdrian Hunter } 1091f6986c95SAdrian Hunter break; 1092601897b5SAdrian Hunter case 'l': 1093601897b5SAdrian Hunter synth_opts->last_branch = true; 1094601897b5SAdrian Hunter synth_opts->last_branch_sz = 1095601897b5SAdrian Hunter PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 1096601897b5SAdrian Hunter while (*p == ' ' || *p == ',') 1097601897b5SAdrian Hunter p += 1; 1098601897b5SAdrian Hunter if (isdigit(*p)) { 1099601897b5SAdrian Hunter unsigned int val; 1100601897b5SAdrian Hunter 1101601897b5SAdrian Hunter val = strtoul(p, &endptr, 10); 1102601897b5SAdrian Hunter p = endptr; 1103601897b5SAdrian Hunter if (!val || 1104601897b5SAdrian Hunter val > PERF_ITRACE_MAX_LAST_BRANCH_SZ) 1105601897b5SAdrian Hunter goto out_err; 1106601897b5SAdrian Hunter synth_opts->last_branch_sz = val; 1107601897b5SAdrian Hunter } 1108601897b5SAdrian Hunter break; 1109d1706b39SAndi Kleen case 's': 1110d1706b39SAndi Kleen synth_opts->initial_skip = strtoul(p, &endptr, 10); 1111d1706b39SAndi Kleen if (p == endptr) 1112d1706b39SAndi Kleen goto out_err; 1113d1706b39SAndi Kleen p = endptr; 1114d1706b39SAndi Kleen break; 1115f6986c95SAdrian Hunter case ' ': 1116f6986c95SAdrian Hunter case ',': 1117f6986c95SAdrian Hunter break; 1118f6986c95SAdrian Hunter default: 1119f6986c95SAdrian Hunter goto out_err; 1120f6986c95SAdrian Hunter } 1121f6986c95SAdrian Hunter } 1122f6986c95SAdrian Hunter out: 1123f6986c95SAdrian Hunter if (synth_opts->instructions) { 1124f70cfa07SAdrian Hunter if (!period_type_set) 1125f6986c95SAdrian Hunter synth_opts->period_type = 1126f6986c95SAdrian Hunter PERF_ITRACE_DEFAULT_PERIOD_TYPE; 1127e1791347SAdrian Hunter if (!period_set) 1128f6986c95SAdrian Hunter synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 1129f6986c95SAdrian Hunter } 1130f6986c95SAdrian Hunter 1131f6986c95SAdrian Hunter return 0; 1132f6986c95SAdrian Hunter 1133f6986c95SAdrian Hunter out_err: 1134f6986c95SAdrian Hunter pr_err("Bad Instruction Tracing options '%s'\n", str); 1135f6986c95SAdrian Hunter return -EINVAL; 1136f6986c95SAdrian Hunter } 1137f6986c95SAdrian Hunter 113885ed4729SAdrian Hunter static const char * const auxtrace_error_type_name[] = { 113985ed4729SAdrian Hunter [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace", 114085ed4729SAdrian Hunter }; 114185ed4729SAdrian Hunter 114285ed4729SAdrian Hunter static const char *auxtrace_error_name(int type) 114385ed4729SAdrian Hunter { 114485ed4729SAdrian Hunter const char *error_type_name = NULL; 114585ed4729SAdrian Hunter 114685ed4729SAdrian Hunter if (type < PERF_AUXTRACE_ERROR_MAX) 114785ed4729SAdrian Hunter error_type_name = auxtrace_error_type_name[type]; 114885ed4729SAdrian Hunter if (!error_type_name) 114985ed4729SAdrian Hunter error_type_name = "unknown AUX"; 115085ed4729SAdrian Hunter return error_type_name; 115185ed4729SAdrian Hunter } 115285ed4729SAdrian Hunter 115385ed4729SAdrian Hunter size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) 115485ed4729SAdrian Hunter { 115585ed4729SAdrian Hunter struct auxtrace_error_event *e = &event->auxtrace_error; 115685ed4729SAdrian Hunter int ret; 115785ed4729SAdrian Hunter 115885ed4729SAdrian Hunter ret = fprintf(fp, " %s error type %u", 115985ed4729SAdrian Hunter auxtrace_error_name(e->type), e->type); 116085ed4729SAdrian Hunter ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n", 116185ed4729SAdrian Hunter e->cpu, e->pid, e->tid, e->ip, e->code, e->msg); 116285ed4729SAdrian Hunter return ret; 116385ed4729SAdrian Hunter } 116485ed4729SAdrian Hunter 116585ed4729SAdrian Hunter void perf_session__auxtrace_error_inc(struct perf_session *session, 116685ed4729SAdrian Hunter union perf_event *event) 116785ed4729SAdrian Hunter { 116885ed4729SAdrian Hunter struct auxtrace_error_event *e = &event->auxtrace_error; 116985ed4729SAdrian Hunter 117085ed4729SAdrian Hunter if (e->type < PERF_AUXTRACE_ERROR_MAX) 117185ed4729SAdrian Hunter session->evlist->stats.nr_auxtrace_errors[e->type] += 1; 117285ed4729SAdrian Hunter } 117385ed4729SAdrian Hunter 117485ed4729SAdrian Hunter void events_stats__auxtrace_error_warn(const struct events_stats *stats) 117585ed4729SAdrian Hunter { 117685ed4729SAdrian Hunter int i; 117785ed4729SAdrian Hunter 117885ed4729SAdrian Hunter for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) { 117985ed4729SAdrian Hunter if (!stats->nr_auxtrace_errors[i]) 118085ed4729SAdrian Hunter continue; 118185ed4729SAdrian Hunter ui__warning("%u %s errors\n", 118285ed4729SAdrian Hunter stats->nr_auxtrace_errors[i], 118385ed4729SAdrian Hunter auxtrace_error_name(i)); 118485ed4729SAdrian Hunter } 118585ed4729SAdrian Hunter } 118685ed4729SAdrian Hunter 1187*89f1688aSJiri Olsa int perf_event__process_auxtrace_error(struct perf_session *session, 1188*89f1688aSJiri Olsa union perf_event *event) 118985ed4729SAdrian Hunter { 119073f75fb1SAdrian Hunter if (auxtrace__dont_decode(session)) 119173f75fb1SAdrian Hunter return 0; 119273f75fb1SAdrian Hunter 119385ed4729SAdrian Hunter perf_event__fprintf_auxtrace_error(event, stdout); 119485ed4729SAdrian Hunter return 0; 119585ed4729SAdrian Hunter } 119685ed4729SAdrian Hunter 1197d20031bbSAdrian Hunter static int __auxtrace_mmap__read(struct auxtrace_mmap *mm, 1198d20031bbSAdrian Hunter struct auxtrace_record *itr, 1199d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn, 1200d20031bbSAdrian Hunter bool snapshot, size_t snapshot_size) 12019e0cc4feSAdrian Hunter { 1202d20031bbSAdrian Hunter u64 head, old = mm->prev, offset, ref; 12039e0cc4feSAdrian Hunter unsigned char *data = mm->base; 12049e0cc4feSAdrian Hunter size_t size, head_off, old_off, len1, len2, padding; 12059e0cc4feSAdrian Hunter union perf_event ev; 12069e0cc4feSAdrian Hunter void *data1, *data2; 12079e0cc4feSAdrian Hunter 1208d20031bbSAdrian Hunter if (snapshot) { 1209d20031bbSAdrian Hunter head = auxtrace_mmap__read_snapshot_head(mm); 1210d20031bbSAdrian Hunter if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data, 1211d20031bbSAdrian Hunter &head, &old)) 1212d20031bbSAdrian Hunter return -1; 1213d20031bbSAdrian Hunter } else { 1214d20031bbSAdrian Hunter head = auxtrace_mmap__read_head(mm); 1215d20031bbSAdrian Hunter } 1216d20031bbSAdrian Hunter 12179e0cc4feSAdrian Hunter if (old == head) 12189e0cc4feSAdrian Hunter return 0; 12199e0cc4feSAdrian Hunter 12209e0cc4feSAdrian Hunter pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n", 12219e0cc4feSAdrian Hunter mm->idx, old, head, head - old); 12229e0cc4feSAdrian Hunter 12239e0cc4feSAdrian Hunter if (mm->mask) { 12249e0cc4feSAdrian Hunter head_off = head & mm->mask; 12259e0cc4feSAdrian Hunter old_off = old & mm->mask; 12269e0cc4feSAdrian Hunter } else { 12279e0cc4feSAdrian Hunter head_off = head % mm->len; 12289e0cc4feSAdrian Hunter old_off = old % mm->len; 12299e0cc4feSAdrian Hunter } 12309e0cc4feSAdrian Hunter 12319e0cc4feSAdrian Hunter if (head_off > old_off) 12329e0cc4feSAdrian Hunter size = head_off - old_off; 12339e0cc4feSAdrian Hunter else 12349e0cc4feSAdrian Hunter size = mm->len - (old_off - head_off); 12359e0cc4feSAdrian Hunter 1236d20031bbSAdrian Hunter if (snapshot && size > snapshot_size) 1237d20031bbSAdrian Hunter size = snapshot_size; 1238d20031bbSAdrian Hunter 12399e0cc4feSAdrian Hunter ref = auxtrace_record__reference(itr); 12409e0cc4feSAdrian Hunter 12419e0cc4feSAdrian Hunter if (head > old || size <= head || mm->mask) { 12429e0cc4feSAdrian Hunter offset = head - size; 12439e0cc4feSAdrian Hunter } else { 12449e0cc4feSAdrian Hunter /* 12459e0cc4feSAdrian Hunter * When the buffer size is not a power of 2, 'head' wraps at the 12469e0cc4feSAdrian Hunter * highest multiple of the buffer size, so we have to subtract 12479e0cc4feSAdrian Hunter * the remainder here. 12489e0cc4feSAdrian Hunter */ 12499e0cc4feSAdrian Hunter u64 rem = (0ULL - mm->len) % mm->len; 12509e0cc4feSAdrian Hunter 12519e0cc4feSAdrian Hunter offset = head - size - rem; 12529e0cc4feSAdrian Hunter } 12539e0cc4feSAdrian Hunter 12549e0cc4feSAdrian Hunter if (size > head_off) { 12559e0cc4feSAdrian Hunter len1 = size - head_off; 12569e0cc4feSAdrian Hunter data1 = &data[mm->len - len1]; 12579e0cc4feSAdrian Hunter len2 = head_off; 12589e0cc4feSAdrian Hunter data2 = &data[0]; 12599e0cc4feSAdrian Hunter } else { 12609e0cc4feSAdrian Hunter len1 = size; 12619e0cc4feSAdrian Hunter data1 = &data[head_off - len1]; 12629e0cc4feSAdrian Hunter len2 = 0; 12639e0cc4feSAdrian Hunter data2 = NULL; 12649e0cc4feSAdrian Hunter } 12659e0cc4feSAdrian Hunter 126683b2ea25SAdrian Hunter if (itr->alignment) { 126783b2ea25SAdrian Hunter unsigned int unwanted = len1 % itr->alignment; 126883b2ea25SAdrian Hunter 126983b2ea25SAdrian Hunter len1 -= unwanted; 127083b2ea25SAdrian Hunter size -= unwanted; 127183b2ea25SAdrian Hunter } 127283b2ea25SAdrian Hunter 12739e0cc4feSAdrian Hunter /* padding must be written by fn() e.g. record__process_auxtrace() */ 12749e0cc4feSAdrian Hunter padding = size & 7; 12759e0cc4feSAdrian Hunter if (padding) 12769e0cc4feSAdrian Hunter padding = 8 - padding; 12779e0cc4feSAdrian Hunter 12789e0cc4feSAdrian Hunter memset(&ev, 0, sizeof(ev)); 12799e0cc4feSAdrian Hunter ev.auxtrace.header.type = PERF_RECORD_AUXTRACE; 12809e0cc4feSAdrian Hunter ev.auxtrace.header.size = sizeof(ev.auxtrace); 12819e0cc4feSAdrian Hunter ev.auxtrace.size = size + padding; 12829e0cc4feSAdrian Hunter ev.auxtrace.offset = offset; 12839e0cc4feSAdrian Hunter ev.auxtrace.reference = ref; 12849e0cc4feSAdrian Hunter ev.auxtrace.idx = mm->idx; 12859e0cc4feSAdrian Hunter ev.auxtrace.tid = mm->tid; 12869e0cc4feSAdrian Hunter ev.auxtrace.cpu = mm->cpu; 12879e0cc4feSAdrian Hunter 12889e0cc4feSAdrian Hunter if (fn(tool, &ev, data1, len1, data2, len2)) 12899e0cc4feSAdrian Hunter return -1; 12909e0cc4feSAdrian Hunter 12919e0cc4feSAdrian Hunter mm->prev = head; 12929e0cc4feSAdrian Hunter 1293d20031bbSAdrian Hunter if (!snapshot) { 12949e0cc4feSAdrian Hunter auxtrace_mmap__write_tail(mm, head); 12959e0cc4feSAdrian Hunter if (itr->read_finish) { 12969e0cc4feSAdrian Hunter int err; 12979e0cc4feSAdrian Hunter 12989e0cc4feSAdrian Hunter err = itr->read_finish(itr, mm->idx); 12999e0cc4feSAdrian Hunter if (err < 0) 13009e0cc4feSAdrian Hunter return err; 13019e0cc4feSAdrian Hunter } 1302d20031bbSAdrian Hunter } 13039e0cc4feSAdrian Hunter 13049e0cc4feSAdrian Hunter return 1; 13059e0cc4feSAdrian Hunter } 1306c3278f02SAdrian Hunter 1307d20031bbSAdrian Hunter int auxtrace_mmap__read(struct auxtrace_mmap *mm, struct auxtrace_record *itr, 1308d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn) 1309d20031bbSAdrian Hunter { 1310d20031bbSAdrian Hunter return __auxtrace_mmap__read(mm, itr, tool, fn, false, 0); 1311d20031bbSAdrian Hunter } 1312d20031bbSAdrian Hunter 1313d20031bbSAdrian Hunter int auxtrace_mmap__read_snapshot(struct auxtrace_mmap *mm, 1314d20031bbSAdrian Hunter struct auxtrace_record *itr, 1315d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn, 1316d20031bbSAdrian Hunter size_t snapshot_size) 1317d20031bbSAdrian Hunter { 1318d20031bbSAdrian Hunter return __auxtrace_mmap__read(mm, itr, tool, fn, true, snapshot_size); 1319d20031bbSAdrian Hunter } 1320d20031bbSAdrian Hunter 1321c3278f02SAdrian Hunter /** 1322c3278f02SAdrian Hunter * struct auxtrace_cache - hash table to implement a cache 1323c3278f02SAdrian Hunter * @hashtable: the hashtable 1324c3278f02SAdrian Hunter * @sz: hashtable size (number of hlists) 1325c3278f02SAdrian Hunter * @entry_size: size of an entry 1326c3278f02SAdrian Hunter * @limit: limit the number of entries to this maximum, when reached the cache 1327c3278f02SAdrian Hunter * is dropped and caching begins again with an empty cache 1328c3278f02SAdrian Hunter * @cnt: current number of entries 1329c3278f02SAdrian Hunter * @bits: hashtable size (@sz = 2^@bits) 1330c3278f02SAdrian Hunter */ 1331c3278f02SAdrian Hunter struct auxtrace_cache { 1332c3278f02SAdrian Hunter struct hlist_head *hashtable; 1333c3278f02SAdrian Hunter size_t sz; 1334c3278f02SAdrian Hunter size_t entry_size; 1335c3278f02SAdrian Hunter size_t limit; 1336c3278f02SAdrian Hunter size_t cnt; 1337c3278f02SAdrian Hunter unsigned int bits; 1338c3278f02SAdrian Hunter }; 1339c3278f02SAdrian Hunter 1340c3278f02SAdrian Hunter struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size, 1341c3278f02SAdrian Hunter unsigned int limit_percent) 1342c3278f02SAdrian Hunter { 1343c3278f02SAdrian Hunter struct auxtrace_cache *c; 1344c3278f02SAdrian Hunter struct hlist_head *ht; 1345c3278f02SAdrian Hunter size_t sz, i; 1346c3278f02SAdrian Hunter 1347c3278f02SAdrian Hunter c = zalloc(sizeof(struct auxtrace_cache)); 1348c3278f02SAdrian Hunter if (!c) 1349c3278f02SAdrian Hunter return NULL; 1350c3278f02SAdrian Hunter 1351c3278f02SAdrian Hunter sz = 1UL << bits; 1352c3278f02SAdrian Hunter 1353c3278f02SAdrian Hunter ht = calloc(sz, sizeof(struct hlist_head)); 1354c3278f02SAdrian Hunter if (!ht) 1355c3278f02SAdrian Hunter goto out_free; 1356c3278f02SAdrian Hunter 1357c3278f02SAdrian Hunter for (i = 0; i < sz; i++) 1358c3278f02SAdrian Hunter INIT_HLIST_HEAD(&ht[i]); 1359c3278f02SAdrian Hunter 1360c3278f02SAdrian Hunter c->hashtable = ht; 1361c3278f02SAdrian Hunter c->sz = sz; 1362c3278f02SAdrian Hunter c->entry_size = entry_size; 1363c3278f02SAdrian Hunter c->limit = (c->sz * limit_percent) / 100; 1364c3278f02SAdrian Hunter c->bits = bits; 1365c3278f02SAdrian Hunter 1366c3278f02SAdrian Hunter return c; 1367c3278f02SAdrian Hunter 1368c3278f02SAdrian Hunter out_free: 1369c3278f02SAdrian Hunter free(c); 1370c3278f02SAdrian Hunter return NULL; 1371c3278f02SAdrian Hunter } 1372c3278f02SAdrian Hunter 1373c3278f02SAdrian Hunter static void auxtrace_cache__drop(struct auxtrace_cache *c) 1374c3278f02SAdrian Hunter { 1375c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry; 1376c3278f02SAdrian Hunter struct hlist_node *tmp; 1377c3278f02SAdrian Hunter size_t i; 1378c3278f02SAdrian Hunter 1379c3278f02SAdrian Hunter if (!c) 1380c3278f02SAdrian Hunter return; 1381c3278f02SAdrian Hunter 1382c3278f02SAdrian Hunter for (i = 0; i < c->sz; i++) { 1383c3278f02SAdrian Hunter hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) { 1384c3278f02SAdrian Hunter hlist_del(&entry->hash); 1385c3278f02SAdrian Hunter auxtrace_cache__free_entry(c, entry); 1386c3278f02SAdrian Hunter } 1387c3278f02SAdrian Hunter } 1388c3278f02SAdrian Hunter 1389c3278f02SAdrian Hunter c->cnt = 0; 1390c3278f02SAdrian Hunter } 1391c3278f02SAdrian Hunter 1392c3278f02SAdrian Hunter void auxtrace_cache__free(struct auxtrace_cache *c) 1393c3278f02SAdrian Hunter { 1394c3278f02SAdrian Hunter if (!c) 1395c3278f02SAdrian Hunter return; 1396c3278f02SAdrian Hunter 1397c3278f02SAdrian Hunter auxtrace_cache__drop(c); 1398c3278f02SAdrian Hunter free(c->hashtable); 1399c3278f02SAdrian Hunter free(c); 1400c3278f02SAdrian Hunter } 1401c3278f02SAdrian Hunter 1402c3278f02SAdrian Hunter void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c) 1403c3278f02SAdrian Hunter { 1404c3278f02SAdrian Hunter return malloc(c->entry_size); 1405c3278f02SAdrian Hunter } 1406c3278f02SAdrian Hunter 1407c3278f02SAdrian Hunter void auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused, 1408c3278f02SAdrian Hunter void *entry) 1409c3278f02SAdrian Hunter { 1410c3278f02SAdrian Hunter free(entry); 1411c3278f02SAdrian Hunter } 1412c3278f02SAdrian Hunter 1413c3278f02SAdrian Hunter int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, 1414c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry) 1415c3278f02SAdrian Hunter { 1416c3278f02SAdrian Hunter if (c->limit && ++c->cnt > c->limit) 1417c3278f02SAdrian Hunter auxtrace_cache__drop(c); 1418c3278f02SAdrian Hunter 1419c3278f02SAdrian Hunter entry->key = key; 1420c3278f02SAdrian Hunter hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]); 1421c3278f02SAdrian Hunter 1422c3278f02SAdrian Hunter return 0; 1423c3278f02SAdrian Hunter } 1424c3278f02SAdrian Hunter 1425c3278f02SAdrian Hunter void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key) 1426c3278f02SAdrian Hunter { 1427c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry; 1428c3278f02SAdrian Hunter struct hlist_head *hlist; 1429c3278f02SAdrian Hunter 1430c3278f02SAdrian Hunter if (!c) 1431c3278f02SAdrian Hunter return NULL; 1432c3278f02SAdrian Hunter 1433c3278f02SAdrian Hunter hlist = &c->hashtable[hash_32(key, c->bits)]; 1434c3278f02SAdrian Hunter hlist_for_each_entry(entry, hlist, hash) { 1435c3278f02SAdrian Hunter if (entry->key == key) 1436c3278f02SAdrian Hunter return entry; 1437c3278f02SAdrian Hunter } 1438c3278f02SAdrian Hunter 1439c3278f02SAdrian Hunter return NULL; 1440c3278f02SAdrian Hunter } 14411b36c03eSAdrian Hunter 14421b36c03eSAdrian Hunter static void addr_filter__free_str(struct addr_filter *filt) 14431b36c03eSAdrian Hunter { 14441b36c03eSAdrian Hunter free(filt->str); 14451b36c03eSAdrian Hunter filt->action = NULL; 14461b36c03eSAdrian Hunter filt->sym_from = NULL; 14471b36c03eSAdrian Hunter filt->sym_to = NULL; 14481b36c03eSAdrian Hunter filt->filename = NULL; 14491b36c03eSAdrian Hunter filt->str = NULL; 14501b36c03eSAdrian Hunter } 14511b36c03eSAdrian Hunter 14521b36c03eSAdrian Hunter static struct addr_filter *addr_filter__new(void) 14531b36c03eSAdrian Hunter { 14541b36c03eSAdrian Hunter struct addr_filter *filt = zalloc(sizeof(*filt)); 14551b36c03eSAdrian Hunter 14561b36c03eSAdrian Hunter if (filt) 14571b36c03eSAdrian Hunter INIT_LIST_HEAD(&filt->list); 14581b36c03eSAdrian Hunter 14591b36c03eSAdrian Hunter return filt; 14601b36c03eSAdrian Hunter } 14611b36c03eSAdrian Hunter 14621b36c03eSAdrian Hunter static void addr_filter__free(struct addr_filter *filt) 14631b36c03eSAdrian Hunter { 14641b36c03eSAdrian Hunter if (filt) 14651b36c03eSAdrian Hunter addr_filter__free_str(filt); 14661b36c03eSAdrian Hunter free(filt); 14671b36c03eSAdrian Hunter } 14681b36c03eSAdrian Hunter 14691b36c03eSAdrian Hunter static void addr_filters__add(struct addr_filters *filts, 14701b36c03eSAdrian Hunter struct addr_filter *filt) 14711b36c03eSAdrian Hunter { 14721b36c03eSAdrian Hunter list_add_tail(&filt->list, &filts->head); 14731b36c03eSAdrian Hunter filts->cnt += 1; 14741b36c03eSAdrian Hunter } 14751b36c03eSAdrian Hunter 14761b36c03eSAdrian Hunter static void addr_filters__del(struct addr_filters *filts, 14771b36c03eSAdrian Hunter struct addr_filter *filt) 14781b36c03eSAdrian Hunter { 14791b36c03eSAdrian Hunter list_del_init(&filt->list); 14801b36c03eSAdrian Hunter filts->cnt -= 1; 14811b36c03eSAdrian Hunter } 14821b36c03eSAdrian Hunter 14831b36c03eSAdrian Hunter void addr_filters__init(struct addr_filters *filts) 14841b36c03eSAdrian Hunter { 14851b36c03eSAdrian Hunter INIT_LIST_HEAD(&filts->head); 14861b36c03eSAdrian Hunter filts->cnt = 0; 14871b36c03eSAdrian Hunter } 14881b36c03eSAdrian Hunter 14891b36c03eSAdrian Hunter void addr_filters__exit(struct addr_filters *filts) 14901b36c03eSAdrian Hunter { 14911b36c03eSAdrian Hunter struct addr_filter *filt, *n; 14921b36c03eSAdrian Hunter 14931b36c03eSAdrian Hunter list_for_each_entry_safe(filt, n, &filts->head, list) { 14941b36c03eSAdrian Hunter addr_filters__del(filts, filt); 14951b36c03eSAdrian Hunter addr_filter__free(filt); 14961b36c03eSAdrian Hunter } 14971b36c03eSAdrian Hunter } 14981b36c03eSAdrian Hunter 14991b36c03eSAdrian Hunter static int parse_num_or_str(char **inp, u64 *num, const char **str, 15001b36c03eSAdrian Hunter const char *str_delim) 15011b36c03eSAdrian Hunter { 15021b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 15031b36c03eSAdrian Hunter 15041b36c03eSAdrian Hunter if (isdigit(**inp)) { 15051b36c03eSAdrian Hunter char *endptr; 15061b36c03eSAdrian Hunter 15071b36c03eSAdrian Hunter if (!num) 15081b36c03eSAdrian Hunter return -EINVAL; 15091b36c03eSAdrian Hunter errno = 0; 15101b36c03eSAdrian Hunter *num = strtoull(*inp, &endptr, 0); 15111b36c03eSAdrian Hunter if (errno) 15121b36c03eSAdrian Hunter return -errno; 15131b36c03eSAdrian Hunter if (endptr == *inp) 15141b36c03eSAdrian Hunter return -EINVAL; 15151b36c03eSAdrian Hunter *inp = endptr; 15161b36c03eSAdrian Hunter } else { 15171b36c03eSAdrian Hunter size_t n; 15181b36c03eSAdrian Hunter 15191b36c03eSAdrian Hunter if (!str) 15201b36c03eSAdrian Hunter return -EINVAL; 15211b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 15221b36c03eSAdrian Hunter *str = *inp; 15231b36c03eSAdrian Hunter n = strcspn(*inp, str_delim); 15241b36c03eSAdrian Hunter if (!n) 15251b36c03eSAdrian Hunter return -EINVAL; 15261b36c03eSAdrian Hunter *inp += n; 15271b36c03eSAdrian Hunter if (**inp) { 15281b36c03eSAdrian Hunter **inp = '\0'; 15291b36c03eSAdrian Hunter *inp += 1; 15301b36c03eSAdrian Hunter } 15311b36c03eSAdrian Hunter } 15321b36c03eSAdrian Hunter return 0; 15331b36c03eSAdrian Hunter } 15341b36c03eSAdrian Hunter 15351b36c03eSAdrian Hunter static int parse_action(struct addr_filter *filt) 15361b36c03eSAdrian Hunter { 15371b36c03eSAdrian Hunter if (!strcmp(filt->action, "filter")) { 15381b36c03eSAdrian Hunter filt->start = true; 15391b36c03eSAdrian Hunter filt->range = true; 15401b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "start")) { 15411b36c03eSAdrian Hunter filt->start = true; 15421b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "stop")) { 15431b36c03eSAdrian Hunter filt->start = false; 15441b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "tracestop")) { 15451b36c03eSAdrian Hunter filt->start = false; 15461b36c03eSAdrian Hunter filt->range = true; 15471b36c03eSAdrian Hunter filt->action += 5; /* Change 'tracestop' to 'stop' */ 15481b36c03eSAdrian Hunter } else { 15491b36c03eSAdrian Hunter return -EINVAL; 15501b36c03eSAdrian Hunter } 15511b36c03eSAdrian Hunter return 0; 15521b36c03eSAdrian Hunter } 15531b36c03eSAdrian Hunter 15541b36c03eSAdrian Hunter static int parse_sym_idx(char **inp, int *idx) 15551b36c03eSAdrian Hunter { 15561b36c03eSAdrian Hunter *idx = -1; 15571b36c03eSAdrian Hunter 15581b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 15591b36c03eSAdrian Hunter 15601b36c03eSAdrian Hunter if (**inp != '#') 15611b36c03eSAdrian Hunter return 0; 15621b36c03eSAdrian Hunter 15631b36c03eSAdrian Hunter *inp += 1; 15641b36c03eSAdrian Hunter 15651b36c03eSAdrian Hunter if (**inp == 'g' || **inp == 'G') { 15661b36c03eSAdrian Hunter *inp += 1; 15671b36c03eSAdrian Hunter *idx = 0; 15681b36c03eSAdrian Hunter } else { 15691b36c03eSAdrian Hunter unsigned long num; 15701b36c03eSAdrian Hunter char *endptr; 15711b36c03eSAdrian Hunter 15721b36c03eSAdrian Hunter errno = 0; 15731b36c03eSAdrian Hunter num = strtoul(*inp, &endptr, 0); 15741b36c03eSAdrian Hunter if (errno) 15751b36c03eSAdrian Hunter return -errno; 15761b36c03eSAdrian Hunter if (endptr == *inp || num > INT_MAX) 15771b36c03eSAdrian Hunter return -EINVAL; 15781b36c03eSAdrian Hunter *inp = endptr; 15791b36c03eSAdrian Hunter *idx = num; 15801b36c03eSAdrian Hunter } 15811b36c03eSAdrian Hunter 15821b36c03eSAdrian Hunter return 0; 15831b36c03eSAdrian Hunter } 15841b36c03eSAdrian Hunter 15851b36c03eSAdrian Hunter static int parse_addr_size(char **inp, u64 *num, const char **str, int *idx) 15861b36c03eSAdrian Hunter { 15871b36c03eSAdrian Hunter int err = parse_num_or_str(inp, num, str, " "); 15881b36c03eSAdrian Hunter 15891b36c03eSAdrian Hunter if (!err && *str) 15901b36c03eSAdrian Hunter err = parse_sym_idx(inp, idx); 15911b36c03eSAdrian Hunter 15921b36c03eSAdrian Hunter return err; 15931b36c03eSAdrian Hunter } 15941b36c03eSAdrian Hunter 15951b36c03eSAdrian Hunter static int parse_one_filter(struct addr_filter *filt, const char **filter_inp) 15961b36c03eSAdrian Hunter { 15971b36c03eSAdrian Hunter char *fstr; 15981b36c03eSAdrian Hunter int err; 15991b36c03eSAdrian Hunter 16001b36c03eSAdrian Hunter filt->str = fstr = strdup(*filter_inp); 16011b36c03eSAdrian Hunter if (!fstr) 16021b36c03eSAdrian Hunter return -ENOMEM; 16031b36c03eSAdrian Hunter 16041b36c03eSAdrian Hunter err = parse_num_or_str(&fstr, NULL, &filt->action, " "); 16051b36c03eSAdrian Hunter if (err) 16061b36c03eSAdrian Hunter goto out_err; 16071b36c03eSAdrian Hunter 16081b36c03eSAdrian Hunter err = parse_action(filt); 16091b36c03eSAdrian Hunter if (err) 16101b36c03eSAdrian Hunter goto out_err; 16111b36c03eSAdrian Hunter 16121b36c03eSAdrian Hunter err = parse_addr_size(&fstr, &filt->addr, &filt->sym_from, 16131b36c03eSAdrian Hunter &filt->sym_from_idx); 16141b36c03eSAdrian Hunter if (err) 16151b36c03eSAdrian Hunter goto out_err; 16161b36c03eSAdrian Hunter 16171b36c03eSAdrian Hunter fstr += strspn(fstr, " "); 16181b36c03eSAdrian Hunter 16191b36c03eSAdrian Hunter if (*fstr == '/') { 16201b36c03eSAdrian Hunter fstr += 1; 16211b36c03eSAdrian Hunter err = parse_addr_size(&fstr, &filt->size, &filt->sym_to, 16221b36c03eSAdrian Hunter &filt->sym_to_idx); 16231b36c03eSAdrian Hunter if (err) 16241b36c03eSAdrian Hunter goto out_err; 16251b36c03eSAdrian Hunter filt->range = true; 16261b36c03eSAdrian Hunter } 16271b36c03eSAdrian Hunter 16281b36c03eSAdrian Hunter fstr += strspn(fstr, " "); 16291b36c03eSAdrian Hunter 16301b36c03eSAdrian Hunter if (*fstr == '@') { 16311b36c03eSAdrian Hunter fstr += 1; 16321b36c03eSAdrian Hunter err = parse_num_or_str(&fstr, NULL, &filt->filename, " ,"); 16331b36c03eSAdrian Hunter if (err) 16341b36c03eSAdrian Hunter goto out_err; 16351b36c03eSAdrian Hunter } 16361b36c03eSAdrian Hunter 16371b36c03eSAdrian Hunter fstr += strspn(fstr, " ,"); 16381b36c03eSAdrian Hunter 16391b36c03eSAdrian Hunter *filter_inp += fstr - filt->str; 16401b36c03eSAdrian Hunter 16411b36c03eSAdrian Hunter return 0; 16421b36c03eSAdrian Hunter 16431b36c03eSAdrian Hunter out_err: 16441b36c03eSAdrian Hunter addr_filter__free_str(filt); 16451b36c03eSAdrian Hunter 16461b36c03eSAdrian Hunter return err; 16471b36c03eSAdrian Hunter } 16481b36c03eSAdrian Hunter 16491b36c03eSAdrian Hunter int addr_filters__parse_bare_filter(struct addr_filters *filts, 16501b36c03eSAdrian Hunter const char *filter) 16511b36c03eSAdrian Hunter { 16521b36c03eSAdrian Hunter struct addr_filter *filt; 16531b36c03eSAdrian Hunter const char *fstr = filter; 16541b36c03eSAdrian Hunter int err; 16551b36c03eSAdrian Hunter 16561b36c03eSAdrian Hunter while (*fstr) { 16571b36c03eSAdrian Hunter filt = addr_filter__new(); 16581b36c03eSAdrian Hunter err = parse_one_filter(filt, &fstr); 16591b36c03eSAdrian Hunter if (err) { 16601b36c03eSAdrian Hunter addr_filter__free(filt); 16611b36c03eSAdrian Hunter addr_filters__exit(filts); 16621b36c03eSAdrian Hunter return err; 16631b36c03eSAdrian Hunter } 16641b36c03eSAdrian Hunter addr_filters__add(filts, filt); 16651b36c03eSAdrian Hunter } 16661b36c03eSAdrian Hunter 16671b36c03eSAdrian Hunter return 0; 16681b36c03eSAdrian Hunter } 16691b36c03eSAdrian Hunter 16701b36c03eSAdrian Hunter struct sym_args { 16711b36c03eSAdrian Hunter const char *name; 16721b36c03eSAdrian Hunter u64 start; 16731b36c03eSAdrian Hunter u64 size; 16741b36c03eSAdrian Hunter int idx; 16751b36c03eSAdrian Hunter int cnt; 16761b36c03eSAdrian Hunter bool started; 16771b36c03eSAdrian Hunter bool global; 16781b36c03eSAdrian Hunter bool selected; 16791b36c03eSAdrian Hunter bool duplicate; 16801b36c03eSAdrian Hunter bool near; 16811b36c03eSAdrian Hunter }; 16821b36c03eSAdrian Hunter 16831b36c03eSAdrian Hunter static bool kern_sym_match(struct sym_args *args, const char *name, char type) 16841b36c03eSAdrian Hunter { 16851b36c03eSAdrian Hunter /* A function with the same name, and global or the n'th found or any */ 1686e85e0e0cSArnaldo Carvalho de Melo return kallsyms__is_function(type) && 16871b36c03eSAdrian Hunter !strcmp(name, args->name) && 16881b36c03eSAdrian Hunter ((args->global && isupper(type)) || 16891b36c03eSAdrian Hunter (args->selected && ++(args->cnt) == args->idx) || 16901b36c03eSAdrian Hunter (!args->global && !args->selected)); 16911b36c03eSAdrian Hunter } 16921b36c03eSAdrian Hunter 16931b36c03eSAdrian Hunter static int find_kern_sym_cb(void *arg, const char *name, char type, u64 start) 16941b36c03eSAdrian Hunter { 16951b36c03eSAdrian Hunter struct sym_args *args = arg; 16961b36c03eSAdrian Hunter 16971b36c03eSAdrian Hunter if (args->started) { 16981b36c03eSAdrian Hunter if (!args->size) 16991b36c03eSAdrian Hunter args->size = start - args->start; 17001b36c03eSAdrian Hunter if (args->selected) { 17011b36c03eSAdrian Hunter if (args->size) 17021b36c03eSAdrian Hunter return 1; 17031b36c03eSAdrian Hunter } else if (kern_sym_match(args, name, type)) { 17041b36c03eSAdrian Hunter args->duplicate = true; 17051b36c03eSAdrian Hunter return 1; 17061b36c03eSAdrian Hunter } 17071b36c03eSAdrian Hunter } else if (kern_sym_match(args, name, type)) { 17081b36c03eSAdrian Hunter args->started = true; 17091b36c03eSAdrian Hunter args->start = start; 17101b36c03eSAdrian Hunter } 17111b36c03eSAdrian Hunter 17121b36c03eSAdrian Hunter return 0; 17131b36c03eSAdrian Hunter } 17141b36c03eSAdrian Hunter 17151b36c03eSAdrian Hunter static int print_kern_sym_cb(void *arg, const char *name, char type, u64 start) 17161b36c03eSAdrian Hunter { 17171b36c03eSAdrian Hunter struct sym_args *args = arg; 17181b36c03eSAdrian Hunter 17191b36c03eSAdrian Hunter if (kern_sym_match(args, name, type)) { 17201b36c03eSAdrian Hunter pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 17211b36c03eSAdrian Hunter ++args->cnt, start, type, name); 17221b36c03eSAdrian Hunter args->near = true; 17231b36c03eSAdrian Hunter } else if (args->near) { 17241b36c03eSAdrian Hunter args->near = false; 17251b36c03eSAdrian Hunter pr_err("\t\twhich is near\t\t%s\n", name); 17261b36c03eSAdrian Hunter } 17271b36c03eSAdrian Hunter 17281b36c03eSAdrian Hunter return 0; 17291b36c03eSAdrian Hunter } 17301b36c03eSAdrian Hunter 17311b36c03eSAdrian Hunter static int sym_not_found_error(const char *sym_name, int idx) 17321b36c03eSAdrian Hunter { 17331b36c03eSAdrian Hunter if (idx > 0) { 17341b36c03eSAdrian Hunter pr_err("N'th occurrence (N=%d) of symbol '%s' not found.\n", 17351b36c03eSAdrian Hunter idx, sym_name); 17361b36c03eSAdrian Hunter } else if (!idx) { 17371b36c03eSAdrian Hunter pr_err("Global symbol '%s' not found.\n", sym_name); 17381b36c03eSAdrian Hunter } else { 17391b36c03eSAdrian Hunter pr_err("Symbol '%s' not found.\n", sym_name); 17401b36c03eSAdrian Hunter } 17411b36c03eSAdrian Hunter pr_err("Note that symbols must be functions.\n"); 17421b36c03eSAdrian Hunter 17431b36c03eSAdrian Hunter return -EINVAL; 17441b36c03eSAdrian Hunter } 17451b36c03eSAdrian Hunter 17461b36c03eSAdrian Hunter static int find_kern_sym(const char *sym_name, u64 *start, u64 *size, int idx) 17471b36c03eSAdrian Hunter { 17481b36c03eSAdrian Hunter struct sym_args args = { 17491b36c03eSAdrian Hunter .name = sym_name, 17501b36c03eSAdrian Hunter .idx = idx, 17511b36c03eSAdrian Hunter .global = !idx, 17521b36c03eSAdrian Hunter .selected = idx > 0, 17531b36c03eSAdrian Hunter }; 17541b36c03eSAdrian Hunter int err; 17551b36c03eSAdrian Hunter 17561b36c03eSAdrian Hunter *start = 0; 17571b36c03eSAdrian Hunter *size = 0; 17581b36c03eSAdrian Hunter 17591b36c03eSAdrian Hunter err = kallsyms__parse("/proc/kallsyms", &args, find_kern_sym_cb); 17601b36c03eSAdrian Hunter if (err < 0) { 17611b36c03eSAdrian Hunter pr_err("Failed to parse /proc/kallsyms\n"); 17621b36c03eSAdrian Hunter return err; 17631b36c03eSAdrian Hunter } 17641b36c03eSAdrian Hunter 17651b36c03eSAdrian Hunter if (args.duplicate) { 17661b36c03eSAdrian Hunter pr_err("Multiple kernel symbols with name '%s'\n", sym_name); 17671b36c03eSAdrian Hunter args.cnt = 0; 17681b36c03eSAdrian Hunter kallsyms__parse("/proc/kallsyms", &args, print_kern_sym_cb); 17691b36c03eSAdrian Hunter pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 17701b36c03eSAdrian Hunter sym_name); 17711b36c03eSAdrian Hunter pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 17721b36c03eSAdrian Hunter return -EINVAL; 17731b36c03eSAdrian Hunter } 17741b36c03eSAdrian Hunter 17751b36c03eSAdrian Hunter if (!args.started) { 17761b36c03eSAdrian Hunter pr_err("Kernel symbol lookup: "); 17771b36c03eSAdrian Hunter return sym_not_found_error(sym_name, idx); 17781b36c03eSAdrian Hunter } 17791b36c03eSAdrian Hunter 17801b36c03eSAdrian Hunter *start = args.start; 17811b36c03eSAdrian Hunter *size = args.size; 17821b36c03eSAdrian Hunter 17831b36c03eSAdrian Hunter return 0; 17841b36c03eSAdrian Hunter } 17851b36c03eSAdrian Hunter 17861b36c03eSAdrian Hunter static int find_entire_kern_cb(void *arg, const char *name __maybe_unused, 17871b36c03eSAdrian Hunter char type, u64 start) 17881b36c03eSAdrian Hunter { 17891b36c03eSAdrian Hunter struct sym_args *args = arg; 17901b36c03eSAdrian Hunter 1791e85e0e0cSArnaldo Carvalho de Melo if (!kallsyms__is_function(type)) 17921b36c03eSAdrian Hunter return 0; 17931b36c03eSAdrian Hunter 17941b36c03eSAdrian Hunter if (!args->started) { 17951b36c03eSAdrian Hunter args->started = true; 17961b36c03eSAdrian Hunter args->start = start; 17971b36c03eSAdrian Hunter } 17981b36c03eSAdrian Hunter /* Don't know exactly where the kernel ends, so we add a page */ 17991b36c03eSAdrian Hunter args->size = round_up(start, page_size) + page_size - args->start; 18001b36c03eSAdrian Hunter 18011b36c03eSAdrian Hunter return 0; 18021b36c03eSAdrian Hunter } 18031b36c03eSAdrian Hunter 18041b36c03eSAdrian Hunter static int addr_filter__entire_kernel(struct addr_filter *filt) 18051b36c03eSAdrian Hunter { 18061b36c03eSAdrian Hunter struct sym_args args = { .started = false }; 18071b36c03eSAdrian Hunter int err; 18081b36c03eSAdrian Hunter 18091b36c03eSAdrian Hunter err = kallsyms__parse("/proc/kallsyms", &args, find_entire_kern_cb); 18101b36c03eSAdrian Hunter if (err < 0 || !args.started) { 18111b36c03eSAdrian Hunter pr_err("Failed to parse /proc/kallsyms\n"); 18121b36c03eSAdrian Hunter return err; 18131b36c03eSAdrian Hunter } 18141b36c03eSAdrian Hunter 18151b36c03eSAdrian Hunter filt->addr = args.start; 18161b36c03eSAdrian Hunter filt->size = args.size; 18171b36c03eSAdrian Hunter 18181b36c03eSAdrian Hunter return 0; 18191b36c03eSAdrian Hunter } 18201b36c03eSAdrian Hunter 18211b36c03eSAdrian Hunter static int check_end_after_start(struct addr_filter *filt, u64 start, u64 size) 18221b36c03eSAdrian Hunter { 18231b36c03eSAdrian Hunter if (start + size >= filt->addr) 18241b36c03eSAdrian Hunter return 0; 18251b36c03eSAdrian Hunter 18261b36c03eSAdrian Hunter if (filt->sym_from) { 18271b36c03eSAdrian Hunter pr_err("Symbol '%s' (0x%"PRIx64") comes before '%s' (0x%"PRIx64")\n", 18281b36c03eSAdrian Hunter filt->sym_to, start, filt->sym_from, filt->addr); 18291b36c03eSAdrian Hunter } else { 18301b36c03eSAdrian Hunter pr_err("Symbol '%s' (0x%"PRIx64") comes before address 0x%"PRIx64")\n", 18311b36c03eSAdrian Hunter filt->sym_to, start, filt->addr); 18321b36c03eSAdrian Hunter } 18331b36c03eSAdrian Hunter 18341b36c03eSAdrian Hunter return -EINVAL; 18351b36c03eSAdrian Hunter } 18361b36c03eSAdrian Hunter 18371b36c03eSAdrian Hunter static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) 18381b36c03eSAdrian Hunter { 18391b36c03eSAdrian Hunter bool no_size = false; 18401b36c03eSAdrian Hunter u64 start, size; 18411b36c03eSAdrian Hunter int err; 18421b36c03eSAdrian Hunter 18431b36c03eSAdrian Hunter if (symbol_conf.kptr_restrict) { 18441b36c03eSAdrian Hunter pr_err("Kernel addresses are restricted. Unable to resolve kernel symbols.\n"); 18451b36c03eSAdrian Hunter return -EINVAL; 18461b36c03eSAdrian Hunter } 18471b36c03eSAdrian Hunter 18481b36c03eSAdrian Hunter if (filt->sym_from && !strcmp(filt->sym_from, "*")) 18491b36c03eSAdrian Hunter return addr_filter__entire_kernel(filt); 18501b36c03eSAdrian Hunter 18511b36c03eSAdrian Hunter if (filt->sym_from) { 18521b36c03eSAdrian Hunter err = find_kern_sym(filt->sym_from, &start, &size, 18531b36c03eSAdrian Hunter filt->sym_from_idx); 18541b36c03eSAdrian Hunter if (err) 18551b36c03eSAdrian Hunter return err; 18561b36c03eSAdrian Hunter filt->addr = start; 18571b36c03eSAdrian Hunter if (filt->range && !filt->size && !filt->sym_to) { 18581b36c03eSAdrian Hunter filt->size = size; 1859c3a0bbc7SAdrian Hunter no_size = !size; 18601b36c03eSAdrian Hunter } 18611b36c03eSAdrian Hunter } 18621b36c03eSAdrian Hunter 18631b36c03eSAdrian Hunter if (filt->sym_to) { 18641b36c03eSAdrian Hunter err = find_kern_sym(filt->sym_to, &start, &size, 18651b36c03eSAdrian Hunter filt->sym_to_idx); 18661b36c03eSAdrian Hunter if (err) 18671b36c03eSAdrian Hunter return err; 18681b36c03eSAdrian Hunter 18691b36c03eSAdrian Hunter err = check_end_after_start(filt, start, size); 18701b36c03eSAdrian Hunter if (err) 18711b36c03eSAdrian Hunter return err; 18721b36c03eSAdrian Hunter filt->size = start + size - filt->addr; 1873c3a0bbc7SAdrian Hunter no_size = !size; 18741b36c03eSAdrian Hunter } 18751b36c03eSAdrian Hunter 18761b36c03eSAdrian Hunter /* The very last symbol in kallsyms does not imply a particular size */ 18771b36c03eSAdrian Hunter if (no_size) { 18781b36c03eSAdrian Hunter pr_err("Cannot determine size of symbol '%s'\n", 18791b36c03eSAdrian Hunter filt->sym_to ? filt->sym_to : filt->sym_from); 18801b36c03eSAdrian Hunter return -EINVAL; 18811b36c03eSAdrian Hunter } 18821b36c03eSAdrian Hunter 18831b36c03eSAdrian Hunter return 0; 18841b36c03eSAdrian Hunter } 18851b36c03eSAdrian Hunter 18861b36c03eSAdrian Hunter static struct dso *load_dso(const char *name) 18871b36c03eSAdrian Hunter { 18881b36c03eSAdrian Hunter struct map *map; 18891b36c03eSAdrian Hunter struct dso *dso; 18901b36c03eSAdrian Hunter 18911b36c03eSAdrian Hunter map = dso__new_map(name); 18921b36c03eSAdrian Hunter if (!map) 18931b36c03eSAdrian Hunter return NULL; 18941b36c03eSAdrian Hunter 18951b36c03eSAdrian Hunter map__load(map); 18961b36c03eSAdrian Hunter 18971b36c03eSAdrian Hunter dso = dso__get(map->dso); 18981b36c03eSAdrian Hunter 18991b36c03eSAdrian Hunter map__put(map); 19001b36c03eSAdrian Hunter 19011b36c03eSAdrian Hunter return dso; 19021b36c03eSAdrian Hunter } 19031b36c03eSAdrian Hunter 19041b36c03eSAdrian Hunter static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt, 19051b36c03eSAdrian Hunter int idx) 19061b36c03eSAdrian Hunter { 19071b36c03eSAdrian Hunter /* Same name, and global or the n'th found or any */ 19081b36c03eSAdrian Hunter return !arch__compare_symbol_names(name, sym->name) && 19091b36c03eSAdrian Hunter ((!idx && sym->binding == STB_GLOBAL) || 19101b36c03eSAdrian Hunter (idx > 0 && ++*cnt == idx) || 19111b36c03eSAdrian Hunter idx < 0); 19121b36c03eSAdrian Hunter } 19131b36c03eSAdrian Hunter 19141b36c03eSAdrian Hunter static void print_duplicate_syms(struct dso *dso, const char *sym_name) 19151b36c03eSAdrian Hunter { 19161b36c03eSAdrian Hunter struct symbol *sym; 19171b36c03eSAdrian Hunter bool near = false; 19181b36c03eSAdrian Hunter int cnt = 0; 19191b36c03eSAdrian Hunter 19201b36c03eSAdrian Hunter pr_err("Multiple symbols with name '%s'\n", sym_name); 19211b36c03eSAdrian Hunter 19225cf88a63SArnaldo Carvalho de Melo sym = dso__first_symbol(dso); 19231b36c03eSAdrian Hunter while (sym) { 19241b36c03eSAdrian Hunter if (dso_sym_match(sym, sym_name, &cnt, -1)) { 19251b36c03eSAdrian Hunter pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 19261b36c03eSAdrian Hunter ++cnt, sym->start, 19271b36c03eSAdrian Hunter sym->binding == STB_GLOBAL ? 'g' : 19281b36c03eSAdrian Hunter sym->binding == STB_LOCAL ? 'l' : 'w', 19291b36c03eSAdrian Hunter sym->name); 19301b36c03eSAdrian Hunter near = true; 19311b36c03eSAdrian Hunter } else if (near) { 19321b36c03eSAdrian Hunter near = false; 19331b36c03eSAdrian Hunter pr_err("\t\twhich is near\t\t%s\n", sym->name); 19341b36c03eSAdrian Hunter } 19351b36c03eSAdrian Hunter sym = dso__next_symbol(sym); 19361b36c03eSAdrian Hunter } 19371b36c03eSAdrian Hunter 19381b36c03eSAdrian Hunter pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 19391b36c03eSAdrian Hunter sym_name); 19401b36c03eSAdrian Hunter pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 19411b36c03eSAdrian Hunter } 19421b36c03eSAdrian Hunter 19431b36c03eSAdrian Hunter static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start, 19441b36c03eSAdrian Hunter u64 *size, int idx) 19451b36c03eSAdrian Hunter { 19461b36c03eSAdrian Hunter struct symbol *sym; 19471b36c03eSAdrian Hunter int cnt = 0; 19481b36c03eSAdrian Hunter 19491b36c03eSAdrian Hunter *start = 0; 19501b36c03eSAdrian Hunter *size = 0; 19511b36c03eSAdrian Hunter 19525cf88a63SArnaldo Carvalho de Melo sym = dso__first_symbol(dso); 19531b36c03eSAdrian Hunter while (sym) { 19541b36c03eSAdrian Hunter if (*start) { 19551b36c03eSAdrian Hunter if (!*size) 19561b36c03eSAdrian Hunter *size = sym->start - *start; 19571b36c03eSAdrian Hunter if (idx > 0) { 19581b36c03eSAdrian Hunter if (*size) 19591b36c03eSAdrian Hunter return 1; 19601b36c03eSAdrian Hunter } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 19611b36c03eSAdrian Hunter print_duplicate_syms(dso, sym_name); 19621b36c03eSAdrian Hunter return -EINVAL; 19631b36c03eSAdrian Hunter } 19641b36c03eSAdrian Hunter } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 19651b36c03eSAdrian Hunter *start = sym->start; 19661b36c03eSAdrian Hunter *size = sym->end - sym->start; 19671b36c03eSAdrian Hunter } 19681b36c03eSAdrian Hunter sym = dso__next_symbol(sym); 19691b36c03eSAdrian Hunter } 19701b36c03eSAdrian Hunter 19711b36c03eSAdrian Hunter if (!*start) 19721b36c03eSAdrian Hunter return sym_not_found_error(sym_name, idx); 19731b36c03eSAdrian Hunter 19741b36c03eSAdrian Hunter return 0; 19751b36c03eSAdrian Hunter } 19761b36c03eSAdrian Hunter 19771b36c03eSAdrian Hunter static int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso) 19781b36c03eSAdrian Hunter { 19795cf88a63SArnaldo Carvalho de Melo struct symbol *first_sym = dso__first_symbol(dso); 19805cf88a63SArnaldo Carvalho de Melo struct symbol *last_sym = dso__last_symbol(dso); 19811b36c03eSAdrian Hunter 19821b36c03eSAdrian Hunter if (!first_sym || !last_sym) { 19831b36c03eSAdrian Hunter pr_err("Failed to determine filter for %s\nNo symbols found.\n", 19841b36c03eSAdrian Hunter filt->filename); 19851b36c03eSAdrian Hunter return -EINVAL; 19861b36c03eSAdrian Hunter } 19871b36c03eSAdrian Hunter 19881b36c03eSAdrian Hunter filt->addr = first_sym->start; 19891b36c03eSAdrian Hunter filt->size = last_sym->end - first_sym->start; 19901b36c03eSAdrian Hunter 19911b36c03eSAdrian Hunter return 0; 19921b36c03eSAdrian Hunter } 19931b36c03eSAdrian Hunter 19941b36c03eSAdrian Hunter static int addr_filter__resolve_syms(struct addr_filter *filt) 19951b36c03eSAdrian Hunter { 19961b36c03eSAdrian Hunter u64 start, size; 19971b36c03eSAdrian Hunter struct dso *dso; 19981b36c03eSAdrian Hunter int err = 0; 19991b36c03eSAdrian Hunter 20001b36c03eSAdrian Hunter if (!filt->sym_from && !filt->sym_to) 20011b36c03eSAdrian Hunter return 0; 20021b36c03eSAdrian Hunter 20031b36c03eSAdrian Hunter if (!filt->filename) 20041b36c03eSAdrian Hunter return addr_filter__resolve_kernel_syms(filt); 20051b36c03eSAdrian Hunter 20061b36c03eSAdrian Hunter dso = load_dso(filt->filename); 20071b36c03eSAdrian Hunter if (!dso) { 20081b36c03eSAdrian Hunter pr_err("Failed to load symbols from: %s\n", filt->filename); 20091b36c03eSAdrian Hunter return -EINVAL; 20101b36c03eSAdrian Hunter } 20111b36c03eSAdrian Hunter 20121b36c03eSAdrian Hunter if (filt->sym_from && !strcmp(filt->sym_from, "*")) { 20131b36c03eSAdrian Hunter err = addr_filter__entire_dso(filt, dso); 20141b36c03eSAdrian Hunter goto put_dso; 20151b36c03eSAdrian Hunter } 20161b36c03eSAdrian Hunter 20171b36c03eSAdrian Hunter if (filt->sym_from) { 20181b36c03eSAdrian Hunter err = find_dso_sym(dso, filt->sym_from, &start, &size, 20191b36c03eSAdrian Hunter filt->sym_from_idx); 20201b36c03eSAdrian Hunter if (err) 20211b36c03eSAdrian Hunter goto put_dso; 20221b36c03eSAdrian Hunter filt->addr = start; 20231b36c03eSAdrian Hunter if (filt->range && !filt->size && !filt->sym_to) 20241b36c03eSAdrian Hunter filt->size = size; 20251b36c03eSAdrian Hunter } 20261b36c03eSAdrian Hunter 20271b36c03eSAdrian Hunter if (filt->sym_to) { 20281b36c03eSAdrian Hunter err = find_dso_sym(dso, filt->sym_to, &start, &size, 20291b36c03eSAdrian Hunter filt->sym_to_idx); 20301b36c03eSAdrian Hunter if (err) 20311b36c03eSAdrian Hunter goto put_dso; 20321b36c03eSAdrian Hunter 20331b36c03eSAdrian Hunter err = check_end_after_start(filt, start, size); 20341b36c03eSAdrian Hunter if (err) 20351b36c03eSAdrian Hunter return err; 20361b36c03eSAdrian Hunter 20371b36c03eSAdrian Hunter filt->size = start + size - filt->addr; 20381b36c03eSAdrian Hunter } 20391b36c03eSAdrian Hunter 20401b36c03eSAdrian Hunter put_dso: 20411b36c03eSAdrian Hunter dso__put(dso); 20421b36c03eSAdrian Hunter 20431b36c03eSAdrian Hunter return err; 20441b36c03eSAdrian Hunter } 20451b36c03eSAdrian Hunter 20461b36c03eSAdrian Hunter static char *addr_filter__to_str(struct addr_filter *filt) 20471b36c03eSAdrian Hunter { 20481b36c03eSAdrian Hunter char filename_buf[PATH_MAX]; 20491b36c03eSAdrian Hunter const char *at = ""; 20501b36c03eSAdrian Hunter const char *fn = ""; 20511b36c03eSAdrian Hunter char *filter; 20521b36c03eSAdrian Hunter int err; 20531b36c03eSAdrian Hunter 20541b36c03eSAdrian Hunter if (filt->filename) { 20551b36c03eSAdrian Hunter at = "@"; 20561b36c03eSAdrian Hunter fn = realpath(filt->filename, filename_buf); 20571b36c03eSAdrian Hunter if (!fn) 20581b36c03eSAdrian Hunter return NULL; 20591b36c03eSAdrian Hunter } 20601b36c03eSAdrian Hunter 20611b36c03eSAdrian Hunter if (filt->range) { 20621b36c03eSAdrian Hunter err = asprintf(&filter, "%s 0x%"PRIx64"/0x%"PRIx64"%s%s", 20631b36c03eSAdrian Hunter filt->action, filt->addr, filt->size, at, fn); 20641b36c03eSAdrian Hunter } else { 20651b36c03eSAdrian Hunter err = asprintf(&filter, "%s 0x%"PRIx64"%s%s", 20661b36c03eSAdrian Hunter filt->action, filt->addr, at, fn); 20671b36c03eSAdrian Hunter } 20681b36c03eSAdrian Hunter 20691b36c03eSAdrian Hunter return err < 0 ? NULL : filter; 20701b36c03eSAdrian Hunter } 20711b36c03eSAdrian Hunter 20721b36c03eSAdrian Hunter static int parse_addr_filter(struct perf_evsel *evsel, const char *filter, 20731b36c03eSAdrian Hunter int max_nr) 20741b36c03eSAdrian Hunter { 20751b36c03eSAdrian Hunter struct addr_filters filts; 20761b36c03eSAdrian Hunter struct addr_filter *filt; 20771b36c03eSAdrian Hunter int err; 20781b36c03eSAdrian Hunter 20791b36c03eSAdrian Hunter addr_filters__init(&filts); 20801b36c03eSAdrian Hunter 20811b36c03eSAdrian Hunter err = addr_filters__parse_bare_filter(&filts, filter); 20821b36c03eSAdrian Hunter if (err) 20831b36c03eSAdrian Hunter goto out_exit; 20841b36c03eSAdrian Hunter 20851b36c03eSAdrian Hunter if (filts.cnt > max_nr) { 20861b36c03eSAdrian Hunter pr_err("Error: number of address filters (%d) exceeds maximum (%d)\n", 20871b36c03eSAdrian Hunter filts.cnt, max_nr); 20881b36c03eSAdrian Hunter err = -EINVAL; 20891b36c03eSAdrian Hunter goto out_exit; 20901b36c03eSAdrian Hunter } 20911b36c03eSAdrian Hunter 20921b36c03eSAdrian Hunter list_for_each_entry(filt, &filts.head, list) { 20931b36c03eSAdrian Hunter char *new_filter; 20941b36c03eSAdrian Hunter 20951b36c03eSAdrian Hunter err = addr_filter__resolve_syms(filt); 20961b36c03eSAdrian Hunter if (err) 20971b36c03eSAdrian Hunter goto out_exit; 20981b36c03eSAdrian Hunter 20991b36c03eSAdrian Hunter new_filter = addr_filter__to_str(filt); 21001b36c03eSAdrian Hunter if (!new_filter) { 21011b36c03eSAdrian Hunter err = -ENOMEM; 21021b36c03eSAdrian Hunter goto out_exit; 21031b36c03eSAdrian Hunter } 21041b36c03eSAdrian Hunter 21051b36c03eSAdrian Hunter if (perf_evsel__append_addr_filter(evsel, new_filter)) { 21061b36c03eSAdrian Hunter err = -ENOMEM; 21071b36c03eSAdrian Hunter goto out_exit; 21081b36c03eSAdrian Hunter } 21091b36c03eSAdrian Hunter } 21101b36c03eSAdrian Hunter 21111b36c03eSAdrian Hunter out_exit: 21121b36c03eSAdrian Hunter addr_filters__exit(&filts); 21131b36c03eSAdrian Hunter 21141b36c03eSAdrian Hunter if (err) { 21151b36c03eSAdrian Hunter pr_err("Failed to parse address filter: '%s'\n", filter); 21161b36c03eSAdrian Hunter pr_err("Filter format is: filter|start|stop|tracestop <start symbol or address> [/ <end symbol or size>] [@<file name>]\n"); 21171b36c03eSAdrian Hunter pr_err("Where multiple filters are separated by space or comma.\n"); 21181b36c03eSAdrian Hunter } 21191b36c03eSAdrian Hunter 21201b36c03eSAdrian Hunter return err; 21211b36c03eSAdrian Hunter } 21221b36c03eSAdrian Hunter 21231b36c03eSAdrian Hunter static struct perf_pmu *perf_evsel__find_pmu(struct perf_evsel *evsel) 21241b36c03eSAdrian Hunter { 21251b36c03eSAdrian Hunter struct perf_pmu *pmu = NULL; 21261b36c03eSAdrian Hunter 21271b36c03eSAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 21281b36c03eSAdrian Hunter if (pmu->type == evsel->attr.type) 21291b36c03eSAdrian Hunter break; 21301b36c03eSAdrian Hunter } 21311b36c03eSAdrian Hunter 21321b36c03eSAdrian Hunter return pmu; 21331b36c03eSAdrian Hunter } 21341b36c03eSAdrian Hunter 21351b36c03eSAdrian Hunter static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) 21361b36c03eSAdrian Hunter { 21371b36c03eSAdrian Hunter struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); 21381b36c03eSAdrian Hunter int nr_addr_filters = 0; 21391b36c03eSAdrian Hunter 21401b36c03eSAdrian Hunter if (!pmu) 21411b36c03eSAdrian Hunter return 0; 21421b36c03eSAdrian Hunter 21431b36c03eSAdrian Hunter perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters); 21441b36c03eSAdrian Hunter 21451b36c03eSAdrian Hunter return nr_addr_filters; 21461b36c03eSAdrian Hunter } 21471b36c03eSAdrian Hunter 21481b36c03eSAdrian Hunter int auxtrace_parse_filters(struct perf_evlist *evlist) 21491b36c03eSAdrian Hunter { 21501b36c03eSAdrian Hunter struct perf_evsel *evsel; 21511b36c03eSAdrian Hunter char *filter; 21521b36c03eSAdrian Hunter int err, max_nr; 21531b36c03eSAdrian Hunter 21541b36c03eSAdrian Hunter evlist__for_each_entry(evlist, evsel) { 21551b36c03eSAdrian Hunter filter = evsel->filter; 21561b36c03eSAdrian Hunter max_nr = perf_evsel__nr_addr_filter(evsel); 21571b36c03eSAdrian Hunter if (!filter || !max_nr) 21581b36c03eSAdrian Hunter continue; 21591b36c03eSAdrian Hunter evsel->filter = NULL; 21601b36c03eSAdrian Hunter err = parse_addr_filter(evsel, filter, max_nr); 21611b36c03eSAdrian Hunter free(filter); 21621b36c03eSAdrian Hunter if (err) 21631b36c03eSAdrian Hunter return err; 21641b36c03eSAdrian Hunter pr_debug("Address filter: %s\n", evsel->filter); 21651b36c03eSAdrian Hunter } 21661b36c03eSAdrian Hunter 21671b36c03eSAdrian Hunter return 0; 21681b36c03eSAdrian Hunter } 2169