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