12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2718c602dSAdrian Hunter /* 3718c602dSAdrian Hunter * auxtrace.c: AUX area trace support 4718c602dSAdrian Hunter * Copyright (c) 2013-2015, Intel Corporation. 5718c602dSAdrian Hunter */ 6718c602dSAdrian Hunter 7fd20e811SArnaldo Carvalho de Melo #include <inttypes.h> 8718c602dSAdrian Hunter #include <sys/types.h> 9718c602dSAdrian Hunter #include <sys/mman.h> 10718c602dSAdrian Hunter #include <stdbool.h> 111b36c03eSAdrian Hunter #include <string.h> 121b36c03eSAdrian Hunter #include <limits.h> 131b36c03eSAdrian Hunter #include <errno.h> 14718c602dSAdrian Hunter 15718c602dSAdrian Hunter #include <linux/kernel.h> 16718c602dSAdrian Hunter #include <linux/perf_event.h> 17718c602dSAdrian Hunter #include <linux/types.h> 18718c602dSAdrian Hunter #include <linux/bitops.h> 19718c602dSAdrian Hunter #include <linux/log2.h> 20e5027893SAdrian Hunter #include <linux/string.h> 2116bd4321SAdrian Hunter #include <linux/time64.h> 22718c602dSAdrian Hunter 23e5027893SAdrian Hunter #include <sys/param.h> 249e0cc4feSAdrian Hunter #include <stdlib.h> 2585ed4729SAdrian Hunter #include <stdio.h> 26e5027893SAdrian Hunter #include <linux/list.h> 277f7c536fSArnaldo Carvalho de Melo #include <linux/zalloc.h> 289e0cc4feSAdrian Hunter 29718c602dSAdrian Hunter #include "../perf.h" 30718c602dSAdrian Hunter #include "evlist.h" 311b36c03eSAdrian Hunter #include "dso.h" 321b36c03eSAdrian Hunter #include "map.h" 331b36c03eSAdrian Hunter #include "pmu.h" 341b36c03eSAdrian Hunter #include "evsel.h" 35718c602dSAdrian Hunter #include "cpumap.h" 367cadca8eSArnaldo Carvalho de Melo #include "symbol.h" 37718c602dSAdrian Hunter #include "thread_map.h" 38718c602dSAdrian Hunter #include "asm/bug.h" 39718c602dSAdrian Hunter #include "auxtrace.h" 40718c602dSAdrian Hunter 41c3278f02SAdrian Hunter #include <linux/hash.h> 42c3278f02SAdrian Hunter 439e0cc4feSAdrian Hunter #include "event.h" 4485ed4729SAdrian Hunter #include "session.h" 459e0cc4feSAdrian Hunter #include "debug.h" 464b6ab94eSJosh Poimboeuf #include <subcmd/parse-options.h> 479e0cc4feSAdrian Hunter 48440a23b3SMathieu Poirier #include "cs-etm.h" 495efb1d54SAdrian Hunter #include "intel-pt.h" 50d0170af7SAdrian Hunter #include "intel-bts.h" 51ffd3d18cSKim Phillips #include "arm-spe.h" 52b96e6615SThomas Richter #include "s390-cpumsf.h" 535efb1d54SAdrian Hunter 543052ba56SArnaldo Carvalho de Melo #include <linux/ctype.h> 553d689ed6SArnaldo Carvalho de Melo #include "symbol/kallsyms.h" 563d689ed6SArnaldo Carvalho de Melo 572e2967f4SAdrian Hunter static bool auxtrace__dont_decode(struct perf_session *session) 582e2967f4SAdrian Hunter { 592e2967f4SAdrian Hunter return !session->itrace_synth_opts || 602e2967f4SAdrian Hunter session->itrace_synth_opts->dont_decode; 612e2967f4SAdrian Hunter } 622e2967f4SAdrian Hunter 63718c602dSAdrian Hunter int auxtrace_mmap__mmap(struct auxtrace_mmap *mm, 64718c602dSAdrian Hunter struct auxtrace_mmap_params *mp, 65718c602dSAdrian Hunter void *userpg, int fd) 66718c602dSAdrian Hunter { 67718c602dSAdrian Hunter struct perf_event_mmap_page *pc = userpg; 68718c602dSAdrian Hunter 69718c602dSAdrian Hunter WARN_ONCE(mm->base, "Uninitialized auxtrace_mmap\n"); 70718c602dSAdrian Hunter 71718c602dSAdrian Hunter mm->userpg = userpg; 72718c602dSAdrian Hunter mm->mask = mp->mask; 73718c602dSAdrian Hunter mm->len = mp->len; 74718c602dSAdrian Hunter mm->prev = 0; 75718c602dSAdrian Hunter mm->idx = mp->idx; 76718c602dSAdrian Hunter mm->tid = mp->tid; 77718c602dSAdrian Hunter mm->cpu = mp->cpu; 78718c602dSAdrian Hunter 79718c602dSAdrian Hunter if (!mp->len) { 80718c602dSAdrian Hunter mm->base = NULL; 81718c602dSAdrian Hunter return 0; 82718c602dSAdrian Hunter } 83718c602dSAdrian Hunter 84a7fde09aSAdrian Hunter #if BITS_PER_LONG != 64 && !defined(HAVE_SYNC_COMPARE_AND_SWAP_SUPPORT) 85a7fde09aSAdrian Hunter pr_err("Cannot use AUX area tracing mmaps\n"); 86a7fde09aSAdrian Hunter return -1; 87a7fde09aSAdrian Hunter #endif 88a7fde09aSAdrian Hunter 89718c602dSAdrian Hunter pc->aux_offset = mp->offset; 90718c602dSAdrian Hunter pc->aux_size = mp->len; 91718c602dSAdrian Hunter 92718c602dSAdrian Hunter mm->base = mmap(NULL, mp->len, mp->prot, MAP_SHARED, fd, mp->offset); 93718c602dSAdrian Hunter if (mm->base == MAP_FAILED) { 94718c602dSAdrian Hunter pr_debug2("failed to mmap AUX area\n"); 95718c602dSAdrian Hunter mm->base = NULL; 96718c602dSAdrian Hunter return -1; 97718c602dSAdrian Hunter } 98718c602dSAdrian Hunter 99718c602dSAdrian Hunter return 0; 100718c602dSAdrian Hunter } 101718c602dSAdrian Hunter 102718c602dSAdrian Hunter void auxtrace_mmap__munmap(struct auxtrace_mmap *mm) 103718c602dSAdrian Hunter { 104718c602dSAdrian Hunter if (mm->base) { 105718c602dSAdrian Hunter munmap(mm->base, mm->len); 106718c602dSAdrian Hunter mm->base = NULL; 107718c602dSAdrian Hunter } 108718c602dSAdrian Hunter } 109718c602dSAdrian Hunter 110718c602dSAdrian Hunter void auxtrace_mmap_params__init(struct auxtrace_mmap_params *mp, 111718c602dSAdrian Hunter off_t auxtrace_offset, 112718c602dSAdrian Hunter unsigned int auxtrace_pages, 113718c602dSAdrian Hunter bool auxtrace_overwrite) 114718c602dSAdrian Hunter { 115718c602dSAdrian Hunter if (auxtrace_pages) { 116718c602dSAdrian Hunter mp->offset = auxtrace_offset; 117718c602dSAdrian Hunter mp->len = auxtrace_pages * (size_t)page_size; 118718c602dSAdrian Hunter mp->mask = is_power_of_2(mp->len) ? mp->len - 1 : 0; 119718c602dSAdrian Hunter mp->prot = PROT_READ | (auxtrace_overwrite ? 0 : PROT_WRITE); 120718c602dSAdrian Hunter pr_debug2("AUX area mmap length %zu\n", mp->len); 121718c602dSAdrian Hunter } else { 122718c602dSAdrian Hunter mp->len = 0; 123718c602dSAdrian Hunter } 124718c602dSAdrian Hunter } 125718c602dSAdrian Hunter 126718c602dSAdrian Hunter void auxtrace_mmap_params__set_idx(struct auxtrace_mmap_params *mp, 127718c602dSAdrian Hunter struct perf_evlist *evlist, int idx, 128718c602dSAdrian Hunter bool per_cpu) 129718c602dSAdrian Hunter { 130718c602dSAdrian Hunter mp->idx = idx; 131718c602dSAdrian Hunter 132718c602dSAdrian Hunter if (per_cpu) { 133718c602dSAdrian Hunter mp->cpu = evlist->cpus->map[idx]; 134718c602dSAdrian Hunter if (evlist->threads) 135e13798c7SJiri Olsa mp->tid = thread_map__pid(evlist->threads, 0); 136718c602dSAdrian Hunter else 137718c602dSAdrian Hunter mp->tid = -1; 138718c602dSAdrian Hunter } else { 139718c602dSAdrian Hunter mp->cpu = -1; 140e13798c7SJiri Olsa mp->tid = thread_map__pid(evlist->threads, idx); 141718c602dSAdrian Hunter } 142718c602dSAdrian Hunter } 1439e0cc4feSAdrian Hunter 144e5027893SAdrian Hunter #define AUXTRACE_INIT_NR_QUEUES 32 145e5027893SAdrian Hunter 146e5027893SAdrian Hunter static struct auxtrace_queue *auxtrace_alloc_queue_array(unsigned int nr_queues) 147e5027893SAdrian Hunter { 148e5027893SAdrian Hunter struct auxtrace_queue *queue_array; 149e5027893SAdrian Hunter unsigned int max_nr_queues, i; 150e5027893SAdrian Hunter 151e5027893SAdrian Hunter max_nr_queues = UINT_MAX / sizeof(struct auxtrace_queue); 152e5027893SAdrian Hunter if (nr_queues > max_nr_queues) 153e5027893SAdrian Hunter return NULL; 154e5027893SAdrian Hunter 155e5027893SAdrian Hunter queue_array = calloc(nr_queues, sizeof(struct auxtrace_queue)); 156e5027893SAdrian Hunter if (!queue_array) 157e5027893SAdrian Hunter return NULL; 158e5027893SAdrian Hunter 159e5027893SAdrian Hunter for (i = 0; i < nr_queues; i++) { 160e5027893SAdrian Hunter INIT_LIST_HEAD(&queue_array[i].head); 161e5027893SAdrian Hunter queue_array[i].priv = NULL; 162e5027893SAdrian Hunter } 163e5027893SAdrian Hunter 164e5027893SAdrian Hunter return queue_array; 165e5027893SAdrian Hunter } 166e5027893SAdrian Hunter 167e5027893SAdrian Hunter int auxtrace_queues__init(struct auxtrace_queues *queues) 168e5027893SAdrian Hunter { 169e5027893SAdrian Hunter queues->nr_queues = AUXTRACE_INIT_NR_QUEUES; 170e5027893SAdrian Hunter queues->queue_array = auxtrace_alloc_queue_array(queues->nr_queues); 171e5027893SAdrian Hunter if (!queues->queue_array) 172e5027893SAdrian Hunter return -ENOMEM; 173e5027893SAdrian Hunter return 0; 174e5027893SAdrian Hunter } 175e5027893SAdrian Hunter 176e5027893SAdrian Hunter static int auxtrace_queues__grow(struct auxtrace_queues *queues, 177e5027893SAdrian Hunter unsigned int new_nr_queues) 178e5027893SAdrian Hunter { 179e5027893SAdrian Hunter unsigned int nr_queues = queues->nr_queues; 180e5027893SAdrian Hunter struct auxtrace_queue *queue_array; 181e5027893SAdrian Hunter unsigned int i; 182e5027893SAdrian Hunter 183e5027893SAdrian Hunter if (!nr_queues) 184e5027893SAdrian Hunter nr_queues = AUXTRACE_INIT_NR_QUEUES; 185e5027893SAdrian Hunter 186e5027893SAdrian Hunter while (nr_queues && nr_queues < new_nr_queues) 187e5027893SAdrian Hunter nr_queues <<= 1; 188e5027893SAdrian Hunter 189e5027893SAdrian Hunter if (nr_queues < queues->nr_queues || nr_queues < new_nr_queues) 190e5027893SAdrian Hunter return -EINVAL; 191e5027893SAdrian Hunter 192e5027893SAdrian Hunter queue_array = auxtrace_alloc_queue_array(nr_queues); 193e5027893SAdrian Hunter if (!queue_array) 194e5027893SAdrian Hunter return -ENOMEM; 195e5027893SAdrian Hunter 196e5027893SAdrian Hunter for (i = 0; i < queues->nr_queues; i++) { 197e5027893SAdrian Hunter list_splice_tail(&queues->queue_array[i].head, 198e5027893SAdrian Hunter &queue_array[i].head); 19999cbbe56SAdrian Hunter queue_array[i].tid = queues->queue_array[i].tid; 20099cbbe56SAdrian Hunter queue_array[i].cpu = queues->queue_array[i].cpu; 20199cbbe56SAdrian Hunter queue_array[i].set = queues->queue_array[i].set; 202e5027893SAdrian Hunter queue_array[i].priv = queues->queue_array[i].priv; 203e5027893SAdrian Hunter } 204e5027893SAdrian Hunter 205e5027893SAdrian Hunter queues->nr_queues = nr_queues; 206e5027893SAdrian Hunter queues->queue_array = queue_array; 207e5027893SAdrian Hunter 208e5027893SAdrian Hunter return 0; 209e5027893SAdrian Hunter } 210e5027893SAdrian Hunter 211e5027893SAdrian Hunter static void *auxtrace_copy_data(u64 size, struct perf_session *session) 212e5027893SAdrian Hunter { 2138ceb41d7SJiri Olsa int fd = perf_data__fd(session->data); 214e5027893SAdrian Hunter void *p; 215e5027893SAdrian Hunter ssize_t ret; 216e5027893SAdrian Hunter 217e5027893SAdrian Hunter if (size > SSIZE_MAX) 218e5027893SAdrian Hunter return NULL; 219e5027893SAdrian Hunter 220e5027893SAdrian Hunter p = malloc(size); 221e5027893SAdrian Hunter if (!p) 222e5027893SAdrian Hunter return NULL; 223e5027893SAdrian Hunter 224e5027893SAdrian Hunter ret = readn(fd, p, size); 225e5027893SAdrian Hunter if (ret != (ssize_t)size) { 226e5027893SAdrian Hunter free(p); 227e5027893SAdrian Hunter return NULL; 228e5027893SAdrian Hunter } 229e5027893SAdrian Hunter 230e5027893SAdrian Hunter return p; 231e5027893SAdrian Hunter } 232e5027893SAdrian Hunter 233a356a597SAdrian Hunter static int auxtrace_queues__queue_buffer(struct auxtrace_queues *queues, 234e5027893SAdrian Hunter unsigned int idx, 235e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 236e5027893SAdrian Hunter { 237e5027893SAdrian Hunter struct auxtrace_queue *queue; 238e5027893SAdrian Hunter int err; 239e5027893SAdrian Hunter 240e5027893SAdrian Hunter if (idx >= queues->nr_queues) { 241e5027893SAdrian Hunter err = auxtrace_queues__grow(queues, idx + 1); 242e5027893SAdrian Hunter if (err) 243e5027893SAdrian Hunter return err; 244e5027893SAdrian Hunter } 245e5027893SAdrian Hunter 246e5027893SAdrian Hunter queue = &queues->queue_array[idx]; 247e5027893SAdrian Hunter 248e5027893SAdrian Hunter if (!queue->set) { 249e5027893SAdrian Hunter queue->set = true; 250e5027893SAdrian Hunter queue->tid = buffer->tid; 251e5027893SAdrian Hunter queue->cpu = buffer->cpu; 252e5027893SAdrian Hunter } else if (buffer->cpu != queue->cpu || buffer->tid != queue->tid) { 253e5027893SAdrian Hunter pr_err("auxtrace queue conflict: cpu %d, tid %d vs cpu %d, tid %d\n", 254e5027893SAdrian Hunter queue->cpu, queue->tid, buffer->cpu, buffer->tid); 255e5027893SAdrian Hunter return -EINVAL; 256e5027893SAdrian Hunter } 257e5027893SAdrian Hunter 258e5027893SAdrian Hunter buffer->buffer_nr = queues->next_buffer_nr++; 259e5027893SAdrian Hunter 260e5027893SAdrian Hunter list_add_tail(&buffer->list, &queue->head); 261e5027893SAdrian Hunter 262e5027893SAdrian Hunter queues->new_data = true; 263e5027893SAdrian Hunter queues->populated = true; 264e5027893SAdrian Hunter 265e5027893SAdrian Hunter return 0; 266e5027893SAdrian Hunter } 267e5027893SAdrian Hunter 268e5027893SAdrian Hunter /* Limit buffers to 32MiB on 32-bit */ 269e5027893SAdrian Hunter #define BUFFER_LIMIT_FOR_32_BIT (32 * 1024 * 1024) 270e5027893SAdrian Hunter 271e5027893SAdrian Hunter static int auxtrace_queues__split_buffer(struct auxtrace_queues *queues, 272e5027893SAdrian Hunter unsigned int idx, 273e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 274e5027893SAdrian Hunter { 275e5027893SAdrian Hunter u64 sz = buffer->size; 276e5027893SAdrian Hunter bool consecutive = false; 277e5027893SAdrian Hunter struct auxtrace_buffer *b; 278e5027893SAdrian Hunter int err; 279e5027893SAdrian Hunter 280e5027893SAdrian Hunter while (sz > BUFFER_LIMIT_FOR_32_BIT) { 281e5027893SAdrian Hunter b = memdup(buffer, sizeof(struct auxtrace_buffer)); 282e5027893SAdrian Hunter if (!b) 283e5027893SAdrian Hunter return -ENOMEM; 284e5027893SAdrian Hunter b->size = BUFFER_LIMIT_FOR_32_BIT; 285e5027893SAdrian Hunter b->consecutive = consecutive; 286a356a597SAdrian Hunter err = auxtrace_queues__queue_buffer(queues, idx, b); 287e5027893SAdrian Hunter if (err) { 288e5027893SAdrian Hunter auxtrace_buffer__free(b); 289e5027893SAdrian Hunter return err; 290e5027893SAdrian Hunter } 291e5027893SAdrian Hunter buffer->data_offset += BUFFER_LIMIT_FOR_32_BIT; 292e5027893SAdrian Hunter sz -= BUFFER_LIMIT_FOR_32_BIT; 293e5027893SAdrian Hunter consecutive = true; 294e5027893SAdrian Hunter } 295e5027893SAdrian Hunter 296e5027893SAdrian Hunter buffer->size = sz; 297e5027893SAdrian Hunter buffer->consecutive = consecutive; 298e5027893SAdrian Hunter 299e5027893SAdrian Hunter return 0; 300e5027893SAdrian Hunter } 301e5027893SAdrian Hunter 302b238db65SAdrian Hunter static bool filter_cpu(struct perf_session *session, int cpu) 303b238db65SAdrian Hunter { 304b238db65SAdrian Hunter unsigned long *cpu_bitmap = session->itrace_synth_opts->cpu_bitmap; 305b238db65SAdrian Hunter 306b238db65SAdrian Hunter return cpu_bitmap && cpu != -1 && !test_bit(cpu, cpu_bitmap); 307b238db65SAdrian Hunter } 308b238db65SAdrian Hunter 309a356a597SAdrian Hunter static int auxtrace_queues__add_buffer(struct auxtrace_queues *queues, 310e5027893SAdrian Hunter struct perf_session *session, 311e5027893SAdrian Hunter unsigned int idx, 3124c454843SAdrian Hunter struct auxtrace_buffer *buffer, 3134c454843SAdrian Hunter struct auxtrace_buffer **buffer_ptr) 314e5027893SAdrian Hunter { 3150d75f123SAdrian Hunter int err = -ENOMEM; 3160d75f123SAdrian Hunter 317b238db65SAdrian Hunter if (filter_cpu(session, buffer->cpu)) 318b238db65SAdrian Hunter return 0; 319b238db65SAdrian Hunter 3200d75f123SAdrian Hunter buffer = memdup(buffer, sizeof(*buffer)); 3210d75f123SAdrian Hunter if (!buffer) 3220d75f123SAdrian Hunter return -ENOMEM; 3234c454843SAdrian Hunter 324e5027893SAdrian Hunter if (session->one_mmap) { 325e5027893SAdrian Hunter buffer->data = buffer->data_offset - session->one_mmap_offset + 326e5027893SAdrian Hunter session->one_mmap_addr; 3278ceb41d7SJiri Olsa } else if (perf_data__is_pipe(session->data)) { 328e5027893SAdrian Hunter buffer->data = auxtrace_copy_data(buffer->size, session); 329e5027893SAdrian Hunter if (!buffer->data) 3300d75f123SAdrian Hunter goto out_free; 331e5027893SAdrian Hunter buffer->data_needs_freeing = true; 332e5027893SAdrian Hunter } else if (BITS_PER_LONG == 32 && 333e5027893SAdrian Hunter buffer->size > BUFFER_LIMIT_FOR_32_BIT) { 334e5027893SAdrian Hunter err = auxtrace_queues__split_buffer(queues, idx, buffer); 335e5027893SAdrian Hunter if (err) 3360d75f123SAdrian Hunter goto out_free; 337e5027893SAdrian Hunter } 338e5027893SAdrian Hunter 3394c454843SAdrian Hunter err = auxtrace_queues__queue_buffer(queues, idx, buffer); 3404c454843SAdrian Hunter if (err) 3410d75f123SAdrian Hunter goto out_free; 3424c454843SAdrian Hunter 3434c454843SAdrian Hunter /* FIXME: Doesn't work for split buffer */ 3444c454843SAdrian Hunter if (buffer_ptr) 3454c454843SAdrian Hunter *buffer_ptr = buffer; 3464c454843SAdrian Hunter 3474c454843SAdrian Hunter return 0; 3480d75f123SAdrian Hunter 3490d75f123SAdrian Hunter out_free: 3500d75f123SAdrian Hunter auxtrace_buffer__free(buffer); 3510d75f123SAdrian Hunter return err; 352e5027893SAdrian Hunter } 353e5027893SAdrian Hunter 354e5027893SAdrian Hunter int auxtrace_queues__add_event(struct auxtrace_queues *queues, 355e5027893SAdrian Hunter struct perf_session *session, 356e5027893SAdrian Hunter union perf_event *event, off_t data_offset, 357e5027893SAdrian Hunter struct auxtrace_buffer **buffer_ptr) 358e5027893SAdrian Hunter { 3590d75f123SAdrian Hunter struct auxtrace_buffer buffer = { 3600d75f123SAdrian Hunter .pid = -1, 3610d75f123SAdrian Hunter .tid = event->auxtrace.tid, 3620d75f123SAdrian Hunter .cpu = event->auxtrace.cpu, 3630d75f123SAdrian Hunter .data_offset = data_offset, 3640d75f123SAdrian Hunter .offset = event->auxtrace.offset, 3650d75f123SAdrian Hunter .reference = event->auxtrace.reference, 3660d75f123SAdrian Hunter .size = event->auxtrace.size, 3670d75f123SAdrian Hunter }; 3680d75f123SAdrian Hunter unsigned int idx = event->auxtrace.idx; 369e5027893SAdrian Hunter 3700d75f123SAdrian Hunter return auxtrace_queues__add_buffer(queues, session, idx, &buffer, 3714c454843SAdrian Hunter buffer_ptr); 372e5027893SAdrian Hunter } 373e5027893SAdrian Hunter 37499fa2984SAdrian Hunter static int auxtrace_queues__add_indexed_event(struct auxtrace_queues *queues, 37599fa2984SAdrian Hunter struct perf_session *session, 37699fa2984SAdrian Hunter off_t file_offset, size_t sz) 37799fa2984SAdrian Hunter { 37899fa2984SAdrian Hunter union perf_event *event; 37999fa2984SAdrian Hunter int err; 38099fa2984SAdrian Hunter char buf[PERF_SAMPLE_MAX_SIZE]; 38199fa2984SAdrian Hunter 38299fa2984SAdrian Hunter err = perf_session__peek_event(session, file_offset, buf, 38399fa2984SAdrian Hunter PERF_SAMPLE_MAX_SIZE, &event, NULL); 38499fa2984SAdrian Hunter if (err) 38599fa2984SAdrian Hunter return err; 38699fa2984SAdrian Hunter 38799fa2984SAdrian Hunter if (event->header.type == PERF_RECORD_AUXTRACE) { 38899fa2984SAdrian Hunter if (event->header.size < sizeof(struct auxtrace_event) || 38999fa2984SAdrian Hunter event->header.size != sz) { 39099fa2984SAdrian Hunter err = -EINVAL; 39199fa2984SAdrian Hunter goto out; 39299fa2984SAdrian Hunter } 39399fa2984SAdrian Hunter file_offset += event->header.size; 39499fa2984SAdrian Hunter err = auxtrace_queues__add_event(queues, session, event, 39599fa2984SAdrian Hunter file_offset, NULL); 39699fa2984SAdrian Hunter } 39799fa2984SAdrian Hunter out: 39899fa2984SAdrian Hunter return err; 39999fa2984SAdrian Hunter } 40099fa2984SAdrian Hunter 401e5027893SAdrian Hunter void auxtrace_queues__free(struct auxtrace_queues *queues) 402e5027893SAdrian Hunter { 403e5027893SAdrian Hunter unsigned int i; 404e5027893SAdrian Hunter 405e5027893SAdrian Hunter for (i = 0; i < queues->nr_queues; i++) { 406e5027893SAdrian Hunter while (!list_empty(&queues->queue_array[i].head)) { 407e5027893SAdrian Hunter struct auxtrace_buffer *buffer; 408e5027893SAdrian Hunter 409e5027893SAdrian Hunter buffer = list_entry(queues->queue_array[i].head.next, 410e5027893SAdrian Hunter struct auxtrace_buffer, list); 411e5027893SAdrian Hunter list_del(&buffer->list); 412e5027893SAdrian Hunter auxtrace_buffer__free(buffer); 413e5027893SAdrian Hunter } 414e5027893SAdrian Hunter } 415e5027893SAdrian Hunter 416e5027893SAdrian Hunter zfree(&queues->queue_array); 417e5027893SAdrian Hunter queues->nr_queues = 0; 418e5027893SAdrian Hunter } 419e5027893SAdrian Hunter 420f9397155SAdrian Hunter static void auxtrace_heapify(struct auxtrace_heap_item *heap_array, 421f9397155SAdrian Hunter unsigned int pos, unsigned int queue_nr, 422f9397155SAdrian Hunter u64 ordinal) 423f9397155SAdrian Hunter { 424f9397155SAdrian Hunter unsigned int parent; 425f9397155SAdrian Hunter 426f9397155SAdrian Hunter while (pos) { 427f9397155SAdrian Hunter parent = (pos - 1) >> 1; 428f9397155SAdrian Hunter if (heap_array[parent].ordinal <= ordinal) 429f9397155SAdrian Hunter break; 430f9397155SAdrian Hunter heap_array[pos] = heap_array[parent]; 431f9397155SAdrian Hunter pos = parent; 432f9397155SAdrian Hunter } 433f9397155SAdrian Hunter heap_array[pos].queue_nr = queue_nr; 434f9397155SAdrian Hunter heap_array[pos].ordinal = ordinal; 435f9397155SAdrian Hunter } 436f9397155SAdrian Hunter 437f9397155SAdrian Hunter int auxtrace_heap__add(struct auxtrace_heap *heap, unsigned int queue_nr, 438f9397155SAdrian Hunter u64 ordinal) 439f9397155SAdrian Hunter { 440f9397155SAdrian Hunter struct auxtrace_heap_item *heap_array; 441f9397155SAdrian Hunter 442f9397155SAdrian Hunter if (queue_nr >= heap->heap_sz) { 443f9397155SAdrian Hunter unsigned int heap_sz = AUXTRACE_INIT_NR_QUEUES; 444f9397155SAdrian Hunter 445f9397155SAdrian Hunter while (heap_sz <= queue_nr) 446f9397155SAdrian Hunter heap_sz <<= 1; 447f9397155SAdrian Hunter heap_array = realloc(heap->heap_array, 448f9397155SAdrian Hunter heap_sz * sizeof(struct auxtrace_heap_item)); 449f9397155SAdrian Hunter if (!heap_array) 450f9397155SAdrian Hunter return -ENOMEM; 451f9397155SAdrian Hunter heap->heap_array = heap_array; 452f9397155SAdrian Hunter heap->heap_sz = heap_sz; 453f9397155SAdrian Hunter } 454f9397155SAdrian Hunter 455f9397155SAdrian Hunter auxtrace_heapify(heap->heap_array, heap->heap_cnt++, queue_nr, ordinal); 456f9397155SAdrian Hunter 457f9397155SAdrian Hunter return 0; 458f9397155SAdrian Hunter } 459f9397155SAdrian Hunter 460f9397155SAdrian Hunter void auxtrace_heap__free(struct auxtrace_heap *heap) 461f9397155SAdrian Hunter { 462f9397155SAdrian Hunter zfree(&heap->heap_array); 463f9397155SAdrian Hunter heap->heap_cnt = 0; 464f9397155SAdrian Hunter heap->heap_sz = 0; 465f9397155SAdrian Hunter } 466f9397155SAdrian Hunter 467f9397155SAdrian Hunter void auxtrace_heap__pop(struct auxtrace_heap *heap) 468f9397155SAdrian Hunter { 469f9397155SAdrian Hunter unsigned int pos, last, heap_cnt = heap->heap_cnt; 470f9397155SAdrian Hunter struct auxtrace_heap_item *heap_array; 471f9397155SAdrian Hunter 472f9397155SAdrian Hunter if (!heap_cnt) 473f9397155SAdrian Hunter return; 474f9397155SAdrian Hunter 475f9397155SAdrian Hunter heap->heap_cnt -= 1; 476f9397155SAdrian Hunter 477f9397155SAdrian Hunter heap_array = heap->heap_array; 478f9397155SAdrian Hunter 479f9397155SAdrian Hunter pos = 0; 480f9397155SAdrian Hunter while (1) { 481f9397155SAdrian Hunter unsigned int left, right; 482f9397155SAdrian Hunter 483f9397155SAdrian Hunter left = (pos << 1) + 1; 484f9397155SAdrian Hunter if (left >= heap_cnt) 485f9397155SAdrian Hunter break; 486f9397155SAdrian Hunter right = left + 1; 487f9397155SAdrian Hunter if (right >= heap_cnt) { 488f9397155SAdrian Hunter heap_array[pos] = heap_array[left]; 489f9397155SAdrian Hunter return; 490f9397155SAdrian Hunter } 491f9397155SAdrian Hunter if (heap_array[left].ordinal < heap_array[right].ordinal) { 492f9397155SAdrian Hunter heap_array[pos] = heap_array[left]; 493f9397155SAdrian Hunter pos = left; 494f9397155SAdrian Hunter } else { 495f9397155SAdrian Hunter heap_array[pos] = heap_array[right]; 496f9397155SAdrian Hunter pos = right; 497f9397155SAdrian Hunter } 498f9397155SAdrian Hunter } 499f9397155SAdrian Hunter 500f9397155SAdrian Hunter last = heap_cnt - 1; 501f9397155SAdrian Hunter auxtrace_heapify(heap_array, pos, heap_array[last].queue_nr, 502f9397155SAdrian Hunter heap_array[last].ordinal); 503f9397155SAdrian Hunter } 504f9397155SAdrian Hunter 50514a05e13SMathieu Poirier size_t auxtrace_record__info_priv_size(struct auxtrace_record *itr, 50614a05e13SMathieu Poirier struct perf_evlist *evlist) 5079e0cc4feSAdrian Hunter { 5089e0cc4feSAdrian Hunter if (itr) 50914a05e13SMathieu Poirier return itr->info_priv_size(itr, evlist); 5109e0cc4feSAdrian Hunter return 0; 5119e0cc4feSAdrian Hunter } 5129e0cc4feSAdrian Hunter 5139e0cc4feSAdrian Hunter static int auxtrace_not_supported(void) 5149e0cc4feSAdrian Hunter { 5159e0cc4feSAdrian Hunter pr_err("AUX area tracing is not supported on this architecture\n"); 5169e0cc4feSAdrian Hunter return -EINVAL; 5179e0cc4feSAdrian Hunter } 5189e0cc4feSAdrian Hunter 5199e0cc4feSAdrian Hunter int auxtrace_record__info_fill(struct auxtrace_record *itr, 5209e0cc4feSAdrian Hunter struct perf_session *session, 5219e0cc4feSAdrian Hunter struct auxtrace_info_event *auxtrace_info, 5229e0cc4feSAdrian Hunter size_t priv_size) 5239e0cc4feSAdrian Hunter { 5249e0cc4feSAdrian Hunter if (itr) 5259e0cc4feSAdrian Hunter return itr->info_fill(itr, session, auxtrace_info, priv_size); 5269e0cc4feSAdrian Hunter return auxtrace_not_supported(); 5279e0cc4feSAdrian Hunter } 5289e0cc4feSAdrian Hunter 5299e0cc4feSAdrian Hunter void auxtrace_record__free(struct auxtrace_record *itr) 5309e0cc4feSAdrian Hunter { 5319e0cc4feSAdrian Hunter if (itr) 5329e0cc4feSAdrian Hunter itr->free(itr); 5339e0cc4feSAdrian Hunter } 5349e0cc4feSAdrian Hunter 535d20031bbSAdrian Hunter int auxtrace_record__snapshot_start(struct auxtrace_record *itr) 536d20031bbSAdrian Hunter { 537d20031bbSAdrian Hunter if (itr && itr->snapshot_start) 538d20031bbSAdrian Hunter return itr->snapshot_start(itr); 539d20031bbSAdrian Hunter return 0; 540d20031bbSAdrian Hunter } 541d20031bbSAdrian Hunter 542d20031bbSAdrian Hunter int auxtrace_record__snapshot_finish(struct auxtrace_record *itr) 543d20031bbSAdrian Hunter { 544d20031bbSAdrian Hunter if (itr && itr->snapshot_finish) 545d20031bbSAdrian Hunter return itr->snapshot_finish(itr); 546d20031bbSAdrian Hunter return 0; 547d20031bbSAdrian Hunter } 548d20031bbSAdrian Hunter 549d20031bbSAdrian Hunter int auxtrace_record__find_snapshot(struct auxtrace_record *itr, int idx, 550d20031bbSAdrian Hunter struct auxtrace_mmap *mm, 551d20031bbSAdrian Hunter unsigned char *data, u64 *head, u64 *old) 552d20031bbSAdrian Hunter { 553d20031bbSAdrian Hunter if (itr && itr->find_snapshot) 554d20031bbSAdrian Hunter return itr->find_snapshot(itr, idx, mm, data, head, old); 555d20031bbSAdrian Hunter return 0; 556d20031bbSAdrian Hunter } 557d20031bbSAdrian Hunter 5589e0cc4feSAdrian Hunter int auxtrace_record__options(struct auxtrace_record *itr, 5599e0cc4feSAdrian Hunter struct perf_evlist *evlist, 5609e0cc4feSAdrian Hunter struct record_opts *opts) 5619e0cc4feSAdrian Hunter { 5629e0cc4feSAdrian Hunter if (itr) 5639e0cc4feSAdrian Hunter return itr->recording_options(itr, evlist, opts); 5649e0cc4feSAdrian Hunter return 0; 5659e0cc4feSAdrian Hunter } 5669e0cc4feSAdrian Hunter 5679e0cc4feSAdrian Hunter u64 auxtrace_record__reference(struct auxtrace_record *itr) 5689e0cc4feSAdrian Hunter { 5699e0cc4feSAdrian Hunter if (itr) 5709e0cc4feSAdrian Hunter return itr->reference(itr); 5719e0cc4feSAdrian Hunter return 0; 5729e0cc4feSAdrian Hunter } 5739e0cc4feSAdrian Hunter 574d20031bbSAdrian Hunter int auxtrace_parse_snapshot_options(struct auxtrace_record *itr, 575d20031bbSAdrian Hunter struct record_opts *opts, const char *str) 576d20031bbSAdrian Hunter { 577d20031bbSAdrian Hunter if (!str) 578d20031bbSAdrian Hunter return 0; 579d20031bbSAdrian Hunter 580d20031bbSAdrian Hunter if (itr) 581d20031bbSAdrian Hunter return itr->parse_snapshot_options(itr, opts, str); 582d20031bbSAdrian Hunter 583d20031bbSAdrian Hunter pr_err("No AUX area tracing to snapshot\n"); 584d20031bbSAdrian Hunter return -EINVAL; 585d20031bbSAdrian Hunter } 586d20031bbSAdrian Hunter 5879e0cc4feSAdrian Hunter struct auxtrace_record *__weak 5889e0cc4feSAdrian Hunter auxtrace_record__init(struct perf_evlist *evlist __maybe_unused, int *err) 5899e0cc4feSAdrian Hunter { 5909e0cc4feSAdrian Hunter *err = 0; 5919e0cc4feSAdrian Hunter return NULL; 5929e0cc4feSAdrian Hunter } 5939e0cc4feSAdrian Hunter 59499fa2984SAdrian Hunter static int auxtrace_index__alloc(struct list_head *head) 59599fa2984SAdrian Hunter { 59699fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 59799fa2984SAdrian Hunter 59899fa2984SAdrian Hunter auxtrace_index = malloc(sizeof(struct auxtrace_index)); 59999fa2984SAdrian Hunter if (!auxtrace_index) 60099fa2984SAdrian Hunter return -ENOMEM; 60199fa2984SAdrian Hunter 60299fa2984SAdrian Hunter auxtrace_index->nr = 0; 60399fa2984SAdrian Hunter INIT_LIST_HEAD(&auxtrace_index->list); 60499fa2984SAdrian Hunter 60599fa2984SAdrian Hunter list_add_tail(&auxtrace_index->list, head); 60699fa2984SAdrian Hunter 60799fa2984SAdrian Hunter return 0; 60899fa2984SAdrian Hunter } 60999fa2984SAdrian Hunter 61099fa2984SAdrian Hunter void auxtrace_index__free(struct list_head *head) 61199fa2984SAdrian Hunter { 61299fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index, *n; 61399fa2984SAdrian Hunter 61499fa2984SAdrian Hunter list_for_each_entry_safe(auxtrace_index, n, head, list) { 61599fa2984SAdrian Hunter list_del(&auxtrace_index->list); 61699fa2984SAdrian Hunter free(auxtrace_index); 61799fa2984SAdrian Hunter } 61899fa2984SAdrian Hunter } 61999fa2984SAdrian Hunter 62099fa2984SAdrian Hunter static struct auxtrace_index *auxtrace_index__last(struct list_head *head) 62199fa2984SAdrian Hunter { 62299fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 62399fa2984SAdrian Hunter int err; 62499fa2984SAdrian Hunter 62599fa2984SAdrian Hunter if (list_empty(head)) { 62699fa2984SAdrian Hunter err = auxtrace_index__alloc(head); 62799fa2984SAdrian Hunter if (err) 62899fa2984SAdrian Hunter return NULL; 62999fa2984SAdrian Hunter } 63099fa2984SAdrian Hunter 63199fa2984SAdrian Hunter auxtrace_index = list_entry(head->prev, struct auxtrace_index, list); 63299fa2984SAdrian Hunter 63399fa2984SAdrian Hunter if (auxtrace_index->nr >= PERF_AUXTRACE_INDEX_ENTRY_COUNT) { 63499fa2984SAdrian Hunter err = auxtrace_index__alloc(head); 63599fa2984SAdrian Hunter if (err) 63699fa2984SAdrian Hunter return NULL; 63799fa2984SAdrian Hunter auxtrace_index = list_entry(head->prev, struct auxtrace_index, 63899fa2984SAdrian Hunter list); 63999fa2984SAdrian Hunter } 64099fa2984SAdrian Hunter 64199fa2984SAdrian Hunter return auxtrace_index; 64299fa2984SAdrian Hunter } 64399fa2984SAdrian Hunter 64499fa2984SAdrian Hunter int auxtrace_index__auxtrace_event(struct list_head *head, 64599fa2984SAdrian Hunter union perf_event *event, off_t file_offset) 64699fa2984SAdrian Hunter { 64799fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 64899fa2984SAdrian Hunter size_t nr; 64999fa2984SAdrian Hunter 65099fa2984SAdrian Hunter auxtrace_index = auxtrace_index__last(head); 65199fa2984SAdrian Hunter if (!auxtrace_index) 65299fa2984SAdrian Hunter return -ENOMEM; 65399fa2984SAdrian Hunter 65499fa2984SAdrian Hunter nr = auxtrace_index->nr; 65599fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = file_offset; 65699fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = event->header.size; 65799fa2984SAdrian Hunter auxtrace_index->nr += 1; 65899fa2984SAdrian Hunter 65999fa2984SAdrian Hunter return 0; 66099fa2984SAdrian Hunter } 66199fa2984SAdrian Hunter 66299fa2984SAdrian Hunter static int auxtrace_index__do_write(int fd, 66399fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index) 66499fa2984SAdrian Hunter { 66599fa2984SAdrian Hunter struct auxtrace_index_entry ent; 66699fa2984SAdrian Hunter size_t i; 66799fa2984SAdrian Hunter 66899fa2984SAdrian Hunter for (i = 0; i < auxtrace_index->nr; i++) { 66999fa2984SAdrian Hunter ent.file_offset = auxtrace_index->entries[i].file_offset; 67099fa2984SAdrian Hunter ent.sz = auxtrace_index->entries[i].sz; 67199fa2984SAdrian Hunter if (writen(fd, &ent, sizeof(ent)) != sizeof(ent)) 67299fa2984SAdrian Hunter return -errno; 67399fa2984SAdrian Hunter } 67499fa2984SAdrian Hunter return 0; 67599fa2984SAdrian Hunter } 67699fa2984SAdrian Hunter 67799fa2984SAdrian Hunter int auxtrace_index__write(int fd, struct list_head *head) 67899fa2984SAdrian Hunter { 67999fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 68099fa2984SAdrian Hunter u64 total = 0; 68199fa2984SAdrian Hunter int err; 68299fa2984SAdrian Hunter 68399fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, head, list) 68499fa2984SAdrian Hunter total += auxtrace_index->nr; 68599fa2984SAdrian Hunter 68699fa2984SAdrian Hunter if (writen(fd, &total, sizeof(total)) != sizeof(total)) 68799fa2984SAdrian Hunter return -errno; 68899fa2984SAdrian Hunter 68999fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, head, list) { 69099fa2984SAdrian Hunter err = auxtrace_index__do_write(fd, auxtrace_index); 69199fa2984SAdrian Hunter if (err) 69299fa2984SAdrian Hunter return err; 69399fa2984SAdrian Hunter } 69499fa2984SAdrian Hunter 69599fa2984SAdrian Hunter return 0; 69699fa2984SAdrian Hunter } 69799fa2984SAdrian Hunter 69899fa2984SAdrian Hunter static int auxtrace_index__process_entry(int fd, struct list_head *head, 69999fa2984SAdrian Hunter bool needs_swap) 70099fa2984SAdrian Hunter { 70199fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 70299fa2984SAdrian Hunter struct auxtrace_index_entry ent; 70399fa2984SAdrian Hunter size_t nr; 70499fa2984SAdrian Hunter 70599fa2984SAdrian Hunter if (readn(fd, &ent, sizeof(ent)) != sizeof(ent)) 70699fa2984SAdrian Hunter return -1; 70799fa2984SAdrian Hunter 70899fa2984SAdrian Hunter auxtrace_index = auxtrace_index__last(head); 70999fa2984SAdrian Hunter if (!auxtrace_index) 71099fa2984SAdrian Hunter return -1; 71199fa2984SAdrian Hunter 71299fa2984SAdrian Hunter nr = auxtrace_index->nr; 71399fa2984SAdrian Hunter if (needs_swap) { 71499fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = 71599fa2984SAdrian Hunter bswap_64(ent.file_offset); 71699fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = bswap_64(ent.sz); 71799fa2984SAdrian Hunter } else { 71899fa2984SAdrian Hunter auxtrace_index->entries[nr].file_offset = ent.file_offset; 71999fa2984SAdrian Hunter auxtrace_index->entries[nr].sz = ent.sz; 72099fa2984SAdrian Hunter } 72199fa2984SAdrian Hunter 72299fa2984SAdrian Hunter auxtrace_index->nr = nr + 1; 72399fa2984SAdrian Hunter 72499fa2984SAdrian Hunter return 0; 72599fa2984SAdrian Hunter } 72699fa2984SAdrian Hunter 72799fa2984SAdrian Hunter int auxtrace_index__process(int fd, u64 size, struct perf_session *session, 72899fa2984SAdrian Hunter bool needs_swap) 72999fa2984SAdrian Hunter { 73099fa2984SAdrian Hunter struct list_head *head = &session->auxtrace_index; 73199fa2984SAdrian Hunter u64 nr; 73299fa2984SAdrian Hunter 73399fa2984SAdrian Hunter if (readn(fd, &nr, sizeof(u64)) != sizeof(u64)) 73499fa2984SAdrian Hunter return -1; 73599fa2984SAdrian Hunter 73699fa2984SAdrian Hunter if (needs_swap) 73799fa2984SAdrian Hunter nr = bswap_64(nr); 73899fa2984SAdrian Hunter 73999fa2984SAdrian Hunter if (sizeof(u64) + nr * sizeof(struct auxtrace_index_entry) > size) 74099fa2984SAdrian Hunter return -1; 74199fa2984SAdrian Hunter 74299fa2984SAdrian Hunter while (nr--) { 74399fa2984SAdrian Hunter int err; 74499fa2984SAdrian Hunter 74599fa2984SAdrian Hunter err = auxtrace_index__process_entry(fd, head, needs_swap); 74699fa2984SAdrian Hunter if (err) 74799fa2984SAdrian Hunter return -1; 74899fa2984SAdrian Hunter } 74999fa2984SAdrian Hunter 75099fa2984SAdrian Hunter return 0; 75199fa2984SAdrian Hunter } 75299fa2984SAdrian Hunter 75399fa2984SAdrian Hunter static int auxtrace_queues__process_index_entry(struct auxtrace_queues *queues, 75499fa2984SAdrian Hunter struct perf_session *session, 75599fa2984SAdrian Hunter struct auxtrace_index_entry *ent) 75699fa2984SAdrian Hunter { 75799fa2984SAdrian Hunter return auxtrace_queues__add_indexed_event(queues, session, 75899fa2984SAdrian Hunter ent->file_offset, ent->sz); 75999fa2984SAdrian Hunter } 76099fa2984SAdrian Hunter 76199fa2984SAdrian Hunter int auxtrace_queues__process_index(struct auxtrace_queues *queues, 76299fa2984SAdrian Hunter struct perf_session *session) 76399fa2984SAdrian Hunter { 76499fa2984SAdrian Hunter struct auxtrace_index *auxtrace_index; 76599fa2984SAdrian Hunter struct auxtrace_index_entry *ent; 76699fa2984SAdrian Hunter size_t i; 76799fa2984SAdrian Hunter int err; 76899fa2984SAdrian Hunter 7692e2967f4SAdrian Hunter if (auxtrace__dont_decode(session)) 7702e2967f4SAdrian Hunter return 0; 7712e2967f4SAdrian Hunter 77299fa2984SAdrian Hunter list_for_each_entry(auxtrace_index, &session->auxtrace_index, list) { 77399fa2984SAdrian Hunter for (i = 0; i < auxtrace_index->nr; i++) { 77499fa2984SAdrian Hunter ent = &auxtrace_index->entries[i]; 77599fa2984SAdrian Hunter err = auxtrace_queues__process_index_entry(queues, 77699fa2984SAdrian Hunter session, 77799fa2984SAdrian Hunter ent); 77899fa2984SAdrian Hunter if (err) 77999fa2984SAdrian Hunter return err; 78099fa2984SAdrian Hunter } 78199fa2984SAdrian Hunter } 78299fa2984SAdrian Hunter return 0; 78399fa2984SAdrian Hunter } 78499fa2984SAdrian Hunter 785e5027893SAdrian Hunter struct auxtrace_buffer *auxtrace_buffer__next(struct auxtrace_queue *queue, 786e5027893SAdrian Hunter struct auxtrace_buffer *buffer) 787e5027893SAdrian Hunter { 788e5027893SAdrian Hunter if (buffer) { 789e5027893SAdrian Hunter if (list_is_last(&buffer->list, &queue->head)) 790e5027893SAdrian Hunter return NULL; 791e5027893SAdrian Hunter return list_entry(buffer->list.next, struct auxtrace_buffer, 792e5027893SAdrian Hunter list); 793e5027893SAdrian Hunter } else { 794e5027893SAdrian Hunter if (list_empty(&queue->head)) 795e5027893SAdrian Hunter return NULL; 796e5027893SAdrian Hunter return list_entry(queue->head.next, struct auxtrace_buffer, 797e5027893SAdrian Hunter list); 798e5027893SAdrian Hunter } 799e5027893SAdrian Hunter } 800e5027893SAdrian Hunter 801e5027893SAdrian Hunter void *auxtrace_buffer__get_data(struct auxtrace_buffer *buffer, int fd) 802e5027893SAdrian Hunter { 803e5027893SAdrian Hunter size_t adj = buffer->data_offset & (page_size - 1); 804e5027893SAdrian Hunter size_t size = buffer->size + adj; 805e5027893SAdrian Hunter off_t file_offset = buffer->data_offset - adj; 806e5027893SAdrian Hunter void *addr; 807e5027893SAdrian Hunter 808e5027893SAdrian Hunter if (buffer->data) 809e5027893SAdrian Hunter return buffer->data; 810e5027893SAdrian Hunter 811e5027893SAdrian Hunter addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, file_offset); 812e5027893SAdrian Hunter if (addr == MAP_FAILED) 813e5027893SAdrian Hunter return NULL; 814e5027893SAdrian Hunter 815e5027893SAdrian Hunter buffer->mmap_addr = addr; 816e5027893SAdrian Hunter buffer->mmap_size = size; 817e5027893SAdrian Hunter 818e5027893SAdrian Hunter buffer->data = addr + adj; 819e5027893SAdrian Hunter 820e5027893SAdrian Hunter return buffer->data; 821e5027893SAdrian Hunter } 822e5027893SAdrian Hunter 823e5027893SAdrian Hunter void auxtrace_buffer__put_data(struct auxtrace_buffer *buffer) 824e5027893SAdrian Hunter { 825e5027893SAdrian Hunter if (!buffer->data || !buffer->mmap_addr) 826e5027893SAdrian Hunter return; 827e5027893SAdrian Hunter munmap(buffer->mmap_addr, buffer->mmap_size); 828e5027893SAdrian Hunter buffer->mmap_addr = NULL; 829e5027893SAdrian Hunter buffer->mmap_size = 0; 830e5027893SAdrian Hunter buffer->data = NULL; 831e5027893SAdrian Hunter buffer->use_data = NULL; 832e5027893SAdrian Hunter } 833e5027893SAdrian Hunter 834e5027893SAdrian Hunter void auxtrace_buffer__drop_data(struct auxtrace_buffer *buffer) 835e5027893SAdrian Hunter { 836e5027893SAdrian Hunter auxtrace_buffer__put_data(buffer); 837e5027893SAdrian Hunter if (buffer->data_needs_freeing) { 838e5027893SAdrian Hunter buffer->data_needs_freeing = false; 839e5027893SAdrian Hunter zfree(&buffer->data); 840e5027893SAdrian Hunter buffer->use_data = NULL; 841e5027893SAdrian Hunter buffer->size = 0; 842e5027893SAdrian Hunter } 843e5027893SAdrian Hunter } 844e5027893SAdrian Hunter 845e5027893SAdrian Hunter void auxtrace_buffer__free(struct auxtrace_buffer *buffer) 846e5027893SAdrian Hunter { 847e5027893SAdrian Hunter auxtrace_buffer__drop_data(buffer); 848e5027893SAdrian Hunter free(buffer); 849e5027893SAdrian Hunter } 850e5027893SAdrian Hunter 85185ed4729SAdrian Hunter void auxtrace_synth_error(struct auxtrace_error_event *auxtrace_error, int type, 85285ed4729SAdrian Hunter int code, int cpu, pid_t pid, pid_t tid, u64 ip, 85316bd4321SAdrian Hunter const char *msg, u64 timestamp) 85485ed4729SAdrian Hunter { 85585ed4729SAdrian Hunter size_t size; 85685ed4729SAdrian Hunter 85785ed4729SAdrian Hunter memset(auxtrace_error, 0, sizeof(struct auxtrace_error_event)); 85885ed4729SAdrian Hunter 85985ed4729SAdrian Hunter auxtrace_error->header.type = PERF_RECORD_AUXTRACE_ERROR; 86085ed4729SAdrian Hunter auxtrace_error->type = type; 86185ed4729SAdrian Hunter auxtrace_error->code = code; 86285ed4729SAdrian Hunter auxtrace_error->cpu = cpu; 86385ed4729SAdrian Hunter auxtrace_error->pid = pid; 86485ed4729SAdrian Hunter auxtrace_error->tid = tid; 86516bd4321SAdrian Hunter auxtrace_error->fmt = 1; 86685ed4729SAdrian Hunter auxtrace_error->ip = ip; 86716bd4321SAdrian Hunter auxtrace_error->time = timestamp; 86885ed4729SAdrian Hunter strlcpy(auxtrace_error->msg, msg, MAX_AUXTRACE_ERROR_MSG); 86985ed4729SAdrian Hunter 87085ed4729SAdrian Hunter size = (void *)auxtrace_error->msg - (void *)auxtrace_error + 87185ed4729SAdrian Hunter strlen(auxtrace_error->msg) + 1; 87285ed4729SAdrian Hunter auxtrace_error->header.size = PERF_ALIGN(size, sizeof(u64)); 87385ed4729SAdrian Hunter } 87485ed4729SAdrian Hunter 8759e0cc4feSAdrian Hunter int perf_event__synthesize_auxtrace_info(struct auxtrace_record *itr, 8769e0cc4feSAdrian Hunter struct perf_tool *tool, 8779e0cc4feSAdrian Hunter struct perf_session *session, 8789e0cc4feSAdrian Hunter perf_event__handler_t process) 8799e0cc4feSAdrian Hunter { 8809e0cc4feSAdrian Hunter union perf_event *ev; 8819e0cc4feSAdrian Hunter size_t priv_size; 8829e0cc4feSAdrian Hunter int err; 8839e0cc4feSAdrian Hunter 8849e0cc4feSAdrian Hunter pr_debug2("Synthesizing auxtrace information\n"); 88514a05e13SMathieu Poirier priv_size = auxtrace_record__info_priv_size(itr, session->evlist); 8869e0cc4feSAdrian Hunter ev = zalloc(sizeof(struct auxtrace_info_event) + priv_size); 8879e0cc4feSAdrian Hunter if (!ev) 8889e0cc4feSAdrian Hunter return -ENOMEM; 8899e0cc4feSAdrian Hunter 8909e0cc4feSAdrian Hunter ev->auxtrace_info.header.type = PERF_RECORD_AUXTRACE_INFO; 8919e0cc4feSAdrian Hunter ev->auxtrace_info.header.size = sizeof(struct auxtrace_info_event) + 8929e0cc4feSAdrian Hunter priv_size; 8939e0cc4feSAdrian Hunter err = auxtrace_record__info_fill(itr, session, &ev->auxtrace_info, 8949e0cc4feSAdrian Hunter priv_size); 8959e0cc4feSAdrian Hunter if (err) 8969e0cc4feSAdrian Hunter goto out_free; 8979e0cc4feSAdrian Hunter 8989e0cc4feSAdrian Hunter err = process(tool, ev, NULL, NULL); 8999e0cc4feSAdrian Hunter out_free: 9009e0cc4feSAdrian Hunter free(ev); 9019e0cc4feSAdrian Hunter return err; 9029e0cc4feSAdrian Hunter } 9039e0cc4feSAdrian Hunter 90489f1688aSJiri Olsa int perf_event__process_auxtrace_info(struct perf_session *session, 90589f1688aSJiri Olsa union perf_event *event) 90673f75fb1SAdrian Hunter { 90773f75fb1SAdrian Hunter enum auxtrace_type type = event->auxtrace_info.type; 90873f75fb1SAdrian Hunter 90973f75fb1SAdrian Hunter if (dump_trace) 91073f75fb1SAdrian Hunter fprintf(stdout, " type: %u\n", type); 91173f75fb1SAdrian Hunter 91273f75fb1SAdrian Hunter switch (type) { 91355ea4ab4SAdrian Hunter case PERF_AUXTRACE_INTEL_PT: 9145efb1d54SAdrian Hunter return intel_pt_process_auxtrace_info(event, session); 915d0170af7SAdrian Hunter case PERF_AUXTRACE_INTEL_BTS: 916d0170af7SAdrian Hunter return intel_bts_process_auxtrace_info(event, session); 917ffd3d18cSKim Phillips case PERF_AUXTRACE_ARM_SPE: 918ffd3d18cSKim Phillips return arm_spe_process_auxtrace_info(event, session); 919a818c563SMathieu Poirier case PERF_AUXTRACE_CS_ETM: 920440a23b3SMathieu Poirier return cs_etm__process_auxtrace_info(event, session); 921b96e6615SThomas Richter case PERF_AUXTRACE_S390_CPUMSF: 922b96e6615SThomas Richter return s390_cpumsf_process_auxtrace_info(event, session); 92373f75fb1SAdrian Hunter case PERF_AUXTRACE_UNKNOWN: 92473f75fb1SAdrian Hunter default: 92573f75fb1SAdrian Hunter return -EINVAL; 92673f75fb1SAdrian Hunter } 92773f75fb1SAdrian Hunter } 92873f75fb1SAdrian Hunter 9297336555aSJiri Olsa s64 perf_event__process_auxtrace(struct perf_session *session, 9307336555aSJiri Olsa union perf_event *event) 93173f75fb1SAdrian Hunter { 93273f75fb1SAdrian Hunter s64 err; 93373f75fb1SAdrian Hunter 93473f75fb1SAdrian Hunter if (dump_trace) 93573f75fb1SAdrian Hunter fprintf(stdout, " size: %#"PRIx64" offset: %#"PRIx64" ref: %#"PRIx64" idx: %u tid: %d cpu: %d\n", 93673f75fb1SAdrian Hunter event->auxtrace.size, event->auxtrace.offset, 93773f75fb1SAdrian Hunter event->auxtrace.reference, event->auxtrace.idx, 93873f75fb1SAdrian Hunter event->auxtrace.tid, event->auxtrace.cpu); 93973f75fb1SAdrian Hunter 94073f75fb1SAdrian Hunter if (auxtrace__dont_decode(session)) 94173f75fb1SAdrian Hunter return event->auxtrace.size; 94273f75fb1SAdrian Hunter 94373f75fb1SAdrian Hunter if (!session->auxtrace || event->header.type != PERF_RECORD_AUXTRACE) 94473f75fb1SAdrian Hunter return -EINVAL; 94573f75fb1SAdrian Hunter 9467336555aSJiri Olsa err = session->auxtrace->process_auxtrace_event(session, event, session->tool); 94773f75fb1SAdrian Hunter if (err < 0) 94873f75fb1SAdrian Hunter return err; 94973f75fb1SAdrian Hunter 95073f75fb1SAdrian Hunter return event->auxtrace.size; 95173f75fb1SAdrian Hunter } 95273f75fb1SAdrian Hunter 953f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD_TYPE PERF_ITRACE_PERIOD_NANOSECS 954f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_PERIOD 100000 955f6986c95SAdrian Hunter #define PERF_ITRACE_DEFAULT_CALLCHAIN_SZ 16 956f6986c95SAdrian Hunter #define PERF_ITRACE_MAX_CALLCHAIN_SZ 1024 957601897b5SAdrian Hunter #define PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ 64 958601897b5SAdrian Hunter #define PERF_ITRACE_MAX_LAST_BRANCH_SZ 1024 959f6986c95SAdrian Hunter 9604eb06815SAndi Kleen void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts, 9614eb06815SAndi Kleen bool no_sample) 962f6986c95SAdrian Hunter { 963f6986c95SAdrian Hunter synth_opts->branches = true; 96453c76b0eSAdrian Hunter synth_opts->transactions = true; 9653bdafdffSAdrian Hunter synth_opts->ptwrites = true; 96670d110d7SAdrian Hunter synth_opts->pwr_events = true; 967f6986c95SAdrian Hunter synth_opts->errors = true; 9684eb06815SAndi Kleen if (no_sample) { 9694eb06815SAndi Kleen synth_opts->period_type = PERF_ITRACE_PERIOD_INSTRUCTIONS; 9704eb06815SAndi Kleen synth_opts->period = 1; 9714eb06815SAndi Kleen synth_opts->calls = true; 9724eb06815SAndi Kleen } else { 9734eb06815SAndi Kleen synth_opts->instructions = true; 974f6986c95SAdrian Hunter synth_opts->period_type = PERF_ITRACE_DEFAULT_PERIOD_TYPE; 975f6986c95SAdrian Hunter synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 9764eb06815SAndi Kleen } 977f6986c95SAdrian Hunter synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 978601897b5SAdrian Hunter synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 979d1706b39SAndi Kleen synth_opts->initial_skip = 0; 980f6986c95SAdrian Hunter } 981f6986c95SAdrian Hunter 982f6986c95SAdrian Hunter /* 983f6986c95SAdrian Hunter * Please check tools/perf/Documentation/perf-script.txt for information 984f6986c95SAdrian Hunter * about the options parsed here, which is introduced after this cset, 985f6986c95SAdrian Hunter * when support in 'perf script' for these options is introduced. 986f6986c95SAdrian Hunter */ 987f6986c95SAdrian Hunter int itrace_parse_synth_opts(const struct option *opt, const char *str, 988f6986c95SAdrian Hunter int unset) 989f6986c95SAdrian Hunter { 990f6986c95SAdrian Hunter struct itrace_synth_opts *synth_opts = opt->value; 991f6986c95SAdrian Hunter const char *p; 992f6986c95SAdrian Hunter char *endptr; 993f70cfa07SAdrian Hunter bool period_type_set = false; 994e1791347SAdrian Hunter bool period_set = false; 995f6986c95SAdrian Hunter 996f6986c95SAdrian Hunter synth_opts->set = true; 997f6986c95SAdrian Hunter 998f6986c95SAdrian Hunter if (unset) { 999f6986c95SAdrian Hunter synth_opts->dont_decode = true; 1000f6986c95SAdrian Hunter return 0; 1001f6986c95SAdrian Hunter } 1002f6986c95SAdrian Hunter 1003f6986c95SAdrian Hunter if (!str) { 1004355200e0SAdrian Hunter itrace_synth_opts__set_default(synth_opts, 1005355200e0SAdrian Hunter synth_opts->default_no_sample); 1006f6986c95SAdrian Hunter return 0; 1007f6986c95SAdrian Hunter } 1008f6986c95SAdrian Hunter 1009f6986c95SAdrian Hunter for (p = str; *p;) { 1010f6986c95SAdrian Hunter switch (*p++) { 1011f6986c95SAdrian Hunter case 'i': 1012f6986c95SAdrian Hunter synth_opts->instructions = true; 1013f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1014f6986c95SAdrian Hunter p += 1; 1015f6986c95SAdrian Hunter if (isdigit(*p)) { 1016f6986c95SAdrian Hunter synth_opts->period = strtoull(p, &endptr, 10); 1017e1791347SAdrian Hunter period_set = true; 1018f6986c95SAdrian Hunter p = endptr; 1019f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1020f6986c95SAdrian Hunter p += 1; 1021f6986c95SAdrian Hunter switch (*p++) { 1022f6986c95SAdrian Hunter case 'i': 1023f6986c95SAdrian Hunter synth_opts->period_type = 1024f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_INSTRUCTIONS; 1025f70cfa07SAdrian Hunter period_type_set = true; 1026f6986c95SAdrian Hunter break; 1027f6986c95SAdrian Hunter case 't': 1028f6986c95SAdrian Hunter synth_opts->period_type = 1029f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_TICKS; 1030f70cfa07SAdrian Hunter period_type_set = true; 1031f6986c95SAdrian Hunter break; 1032f6986c95SAdrian Hunter case 'm': 1033f6986c95SAdrian Hunter synth_opts->period *= 1000; 1034f6986c95SAdrian Hunter /* Fall through */ 1035f6986c95SAdrian Hunter case 'u': 1036f6986c95SAdrian Hunter synth_opts->period *= 1000; 1037f6986c95SAdrian Hunter /* Fall through */ 1038f6986c95SAdrian Hunter case 'n': 1039f6986c95SAdrian Hunter if (*p++ != 's') 1040f6986c95SAdrian Hunter goto out_err; 1041f6986c95SAdrian Hunter synth_opts->period_type = 1042f6986c95SAdrian Hunter PERF_ITRACE_PERIOD_NANOSECS; 1043f70cfa07SAdrian Hunter period_type_set = true; 1044f6986c95SAdrian Hunter break; 1045f6986c95SAdrian Hunter case '\0': 1046f6986c95SAdrian Hunter goto out; 1047f6986c95SAdrian Hunter default: 1048f6986c95SAdrian Hunter goto out_err; 1049f6986c95SAdrian Hunter } 1050f6986c95SAdrian Hunter } 1051f6986c95SAdrian Hunter break; 1052f6986c95SAdrian Hunter case 'b': 1053f6986c95SAdrian Hunter synth_opts->branches = true; 1054f6986c95SAdrian Hunter break; 105553c76b0eSAdrian Hunter case 'x': 105653c76b0eSAdrian Hunter synth_opts->transactions = true; 105753c76b0eSAdrian Hunter break; 10583bdafdffSAdrian Hunter case 'w': 10593bdafdffSAdrian Hunter synth_opts->ptwrites = true; 10603bdafdffSAdrian Hunter break; 106170d110d7SAdrian Hunter case 'p': 106270d110d7SAdrian Hunter synth_opts->pwr_events = true; 106370d110d7SAdrian Hunter break; 1064f6986c95SAdrian Hunter case 'e': 1065f6986c95SAdrian Hunter synth_opts->errors = true; 1066f6986c95SAdrian Hunter break; 1067f6986c95SAdrian Hunter case 'd': 1068f6986c95SAdrian Hunter synth_opts->log = true; 1069f6986c95SAdrian Hunter break; 1070f6986c95SAdrian Hunter case 'c': 1071f6986c95SAdrian Hunter synth_opts->branches = true; 1072f6986c95SAdrian Hunter synth_opts->calls = true; 1073f6986c95SAdrian Hunter break; 1074f6986c95SAdrian Hunter case 'r': 1075f6986c95SAdrian Hunter synth_opts->branches = true; 1076f6986c95SAdrian Hunter synth_opts->returns = true; 1077f6986c95SAdrian Hunter break; 1078f6986c95SAdrian Hunter case 'g': 1079f6986c95SAdrian Hunter synth_opts->callchain = true; 1080f6986c95SAdrian Hunter synth_opts->callchain_sz = 1081f6986c95SAdrian Hunter PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; 1082f6986c95SAdrian Hunter while (*p == ' ' || *p == ',') 1083f6986c95SAdrian Hunter p += 1; 1084f6986c95SAdrian Hunter if (isdigit(*p)) { 1085f6986c95SAdrian Hunter unsigned int val; 1086f6986c95SAdrian Hunter 1087f6986c95SAdrian Hunter val = strtoul(p, &endptr, 10); 1088f6986c95SAdrian Hunter p = endptr; 1089f6986c95SAdrian Hunter if (!val || val > PERF_ITRACE_MAX_CALLCHAIN_SZ) 1090f6986c95SAdrian Hunter goto out_err; 1091f6986c95SAdrian Hunter synth_opts->callchain_sz = val; 1092f6986c95SAdrian Hunter } 1093f6986c95SAdrian Hunter break; 1094601897b5SAdrian Hunter case 'l': 1095601897b5SAdrian Hunter synth_opts->last_branch = true; 1096601897b5SAdrian Hunter synth_opts->last_branch_sz = 1097601897b5SAdrian Hunter PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; 1098601897b5SAdrian Hunter while (*p == ' ' || *p == ',') 1099601897b5SAdrian Hunter p += 1; 1100601897b5SAdrian Hunter if (isdigit(*p)) { 1101601897b5SAdrian Hunter unsigned int val; 1102601897b5SAdrian Hunter 1103601897b5SAdrian Hunter val = strtoul(p, &endptr, 10); 1104601897b5SAdrian Hunter p = endptr; 1105601897b5SAdrian Hunter if (!val || 1106601897b5SAdrian Hunter val > PERF_ITRACE_MAX_LAST_BRANCH_SZ) 1107601897b5SAdrian Hunter goto out_err; 1108601897b5SAdrian Hunter synth_opts->last_branch_sz = val; 1109601897b5SAdrian Hunter } 1110601897b5SAdrian Hunter break; 1111d1706b39SAndi Kleen case 's': 1112d1706b39SAndi Kleen synth_opts->initial_skip = strtoul(p, &endptr, 10); 1113d1706b39SAndi Kleen if (p == endptr) 1114d1706b39SAndi Kleen goto out_err; 1115d1706b39SAndi Kleen p = endptr; 1116d1706b39SAndi Kleen break; 1117f6986c95SAdrian Hunter case ' ': 1118f6986c95SAdrian Hunter case ',': 1119f6986c95SAdrian Hunter break; 1120f6986c95SAdrian Hunter default: 1121f6986c95SAdrian Hunter goto out_err; 1122f6986c95SAdrian Hunter } 1123f6986c95SAdrian Hunter } 1124f6986c95SAdrian Hunter out: 1125f6986c95SAdrian Hunter if (synth_opts->instructions) { 1126f70cfa07SAdrian Hunter if (!period_type_set) 1127f6986c95SAdrian Hunter synth_opts->period_type = 1128f6986c95SAdrian Hunter PERF_ITRACE_DEFAULT_PERIOD_TYPE; 1129e1791347SAdrian Hunter if (!period_set) 1130f6986c95SAdrian Hunter synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; 1131f6986c95SAdrian Hunter } 1132f6986c95SAdrian Hunter 1133f6986c95SAdrian Hunter return 0; 1134f6986c95SAdrian Hunter 1135f6986c95SAdrian Hunter out_err: 1136f6986c95SAdrian Hunter pr_err("Bad Instruction Tracing options '%s'\n", str); 1137f6986c95SAdrian Hunter return -EINVAL; 1138f6986c95SAdrian Hunter } 1139f6986c95SAdrian Hunter 114085ed4729SAdrian Hunter static const char * const auxtrace_error_type_name[] = { 114185ed4729SAdrian Hunter [PERF_AUXTRACE_ERROR_ITRACE] = "instruction trace", 114285ed4729SAdrian Hunter }; 114385ed4729SAdrian Hunter 114485ed4729SAdrian Hunter static const char *auxtrace_error_name(int type) 114585ed4729SAdrian Hunter { 114685ed4729SAdrian Hunter const char *error_type_name = NULL; 114785ed4729SAdrian Hunter 114885ed4729SAdrian Hunter if (type < PERF_AUXTRACE_ERROR_MAX) 114985ed4729SAdrian Hunter error_type_name = auxtrace_error_type_name[type]; 115085ed4729SAdrian Hunter if (!error_type_name) 115185ed4729SAdrian Hunter error_type_name = "unknown AUX"; 115285ed4729SAdrian Hunter return error_type_name; 115385ed4729SAdrian Hunter } 115485ed4729SAdrian Hunter 115585ed4729SAdrian Hunter size_t perf_event__fprintf_auxtrace_error(union perf_event *event, FILE *fp) 115685ed4729SAdrian Hunter { 115785ed4729SAdrian Hunter struct auxtrace_error_event *e = &event->auxtrace_error; 115816bd4321SAdrian Hunter unsigned long long nsecs = e->time; 115916bd4321SAdrian Hunter const char *msg = e->msg; 116085ed4729SAdrian Hunter int ret; 116185ed4729SAdrian Hunter 116285ed4729SAdrian Hunter ret = fprintf(fp, " %s error type %u", 116385ed4729SAdrian Hunter auxtrace_error_name(e->type), e->type); 116416bd4321SAdrian Hunter 116516bd4321SAdrian Hunter if (e->fmt && nsecs) { 116616bd4321SAdrian Hunter unsigned long secs = nsecs / NSEC_PER_SEC; 116716bd4321SAdrian Hunter 116816bd4321SAdrian Hunter nsecs -= secs * NSEC_PER_SEC; 116916bd4321SAdrian Hunter ret += fprintf(fp, " time %lu.%09llu", secs, nsecs); 117016bd4321SAdrian Hunter } else { 117116bd4321SAdrian Hunter ret += fprintf(fp, " time 0"); 117216bd4321SAdrian Hunter } 117316bd4321SAdrian Hunter 117416bd4321SAdrian Hunter if (!e->fmt) 117516bd4321SAdrian Hunter msg = (const char *)&e->time; 117616bd4321SAdrian Hunter 117785ed4729SAdrian Hunter ret += fprintf(fp, " cpu %d pid %d tid %d ip %#"PRIx64" code %u: %s\n", 117816bd4321SAdrian Hunter e->cpu, e->pid, e->tid, e->ip, e->code, msg); 117985ed4729SAdrian Hunter return ret; 118085ed4729SAdrian Hunter } 118185ed4729SAdrian Hunter 118285ed4729SAdrian Hunter void perf_session__auxtrace_error_inc(struct perf_session *session, 118385ed4729SAdrian Hunter union perf_event *event) 118485ed4729SAdrian Hunter { 118585ed4729SAdrian Hunter struct auxtrace_error_event *e = &event->auxtrace_error; 118685ed4729SAdrian Hunter 118785ed4729SAdrian Hunter if (e->type < PERF_AUXTRACE_ERROR_MAX) 118885ed4729SAdrian Hunter session->evlist->stats.nr_auxtrace_errors[e->type] += 1; 118985ed4729SAdrian Hunter } 119085ed4729SAdrian Hunter 119185ed4729SAdrian Hunter void events_stats__auxtrace_error_warn(const struct events_stats *stats) 119285ed4729SAdrian Hunter { 119385ed4729SAdrian Hunter int i; 119485ed4729SAdrian Hunter 119585ed4729SAdrian Hunter for (i = 0; i < PERF_AUXTRACE_ERROR_MAX; i++) { 119685ed4729SAdrian Hunter if (!stats->nr_auxtrace_errors[i]) 119785ed4729SAdrian Hunter continue; 119885ed4729SAdrian Hunter ui__warning("%u %s errors\n", 119985ed4729SAdrian Hunter stats->nr_auxtrace_errors[i], 120085ed4729SAdrian Hunter auxtrace_error_name(i)); 120185ed4729SAdrian Hunter } 120285ed4729SAdrian Hunter } 120385ed4729SAdrian Hunter 120489f1688aSJiri Olsa int perf_event__process_auxtrace_error(struct perf_session *session, 120589f1688aSJiri Olsa union perf_event *event) 120685ed4729SAdrian Hunter { 120773f75fb1SAdrian Hunter if (auxtrace__dont_decode(session)) 120873f75fb1SAdrian Hunter return 0; 120973f75fb1SAdrian Hunter 121085ed4729SAdrian Hunter perf_event__fprintf_auxtrace_error(event, stdout); 121185ed4729SAdrian Hunter return 0; 121285ed4729SAdrian Hunter } 121385ed4729SAdrian Hunter 1214e035f4caSJiri Olsa static int __auxtrace_mmap__read(struct perf_mmap *map, 1215d20031bbSAdrian Hunter struct auxtrace_record *itr, 1216d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn, 1217d20031bbSAdrian Hunter bool snapshot, size_t snapshot_size) 12189e0cc4feSAdrian Hunter { 1219e035f4caSJiri Olsa struct auxtrace_mmap *mm = &map->auxtrace_mmap; 1220d20031bbSAdrian Hunter u64 head, old = mm->prev, offset, ref; 12219e0cc4feSAdrian Hunter unsigned char *data = mm->base; 12229e0cc4feSAdrian Hunter size_t size, head_off, old_off, len1, len2, padding; 12239e0cc4feSAdrian Hunter union perf_event ev; 12249e0cc4feSAdrian Hunter void *data1, *data2; 12259e0cc4feSAdrian Hunter 1226d20031bbSAdrian Hunter if (snapshot) { 1227d20031bbSAdrian Hunter head = auxtrace_mmap__read_snapshot_head(mm); 1228d20031bbSAdrian Hunter if (auxtrace_record__find_snapshot(itr, mm->idx, mm, data, 1229d20031bbSAdrian Hunter &head, &old)) 1230d20031bbSAdrian Hunter return -1; 1231d20031bbSAdrian Hunter } else { 1232d20031bbSAdrian Hunter head = auxtrace_mmap__read_head(mm); 1233d20031bbSAdrian Hunter } 1234d20031bbSAdrian Hunter 12359e0cc4feSAdrian Hunter if (old == head) 12369e0cc4feSAdrian Hunter return 0; 12379e0cc4feSAdrian Hunter 12389e0cc4feSAdrian Hunter pr_debug3("auxtrace idx %d old %#"PRIx64" head %#"PRIx64" diff %#"PRIx64"\n", 12399e0cc4feSAdrian Hunter mm->idx, old, head, head - old); 12409e0cc4feSAdrian Hunter 12419e0cc4feSAdrian Hunter if (mm->mask) { 12429e0cc4feSAdrian Hunter head_off = head & mm->mask; 12439e0cc4feSAdrian Hunter old_off = old & mm->mask; 12449e0cc4feSAdrian Hunter } else { 12459e0cc4feSAdrian Hunter head_off = head % mm->len; 12469e0cc4feSAdrian Hunter old_off = old % mm->len; 12479e0cc4feSAdrian Hunter } 12489e0cc4feSAdrian Hunter 12499e0cc4feSAdrian Hunter if (head_off > old_off) 12509e0cc4feSAdrian Hunter size = head_off - old_off; 12519e0cc4feSAdrian Hunter else 12529e0cc4feSAdrian Hunter size = mm->len - (old_off - head_off); 12539e0cc4feSAdrian Hunter 1254d20031bbSAdrian Hunter if (snapshot && size > snapshot_size) 1255d20031bbSAdrian Hunter size = snapshot_size; 1256d20031bbSAdrian Hunter 12579e0cc4feSAdrian Hunter ref = auxtrace_record__reference(itr); 12589e0cc4feSAdrian Hunter 12599e0cc4feSAdrian Hunter if (head > old || size <= head || mm->mask) { 12609e0cc4feSAdrian Hunter offset = head - size; 12619e0cc4feSAdrian Hunter } else { 12629e0cc4feSAdrian Hunter /* 12639e0cc4feSAdrian Hunter * When the buffer size is not a power of 2, 'head' wraps at the 12649e0cc4feSAdrian Hunter * highest multiple of the buffer size, so we have to subtract 12659e0cc4feSAdrian Hunter * the remainder here. 12669e0cc4feSAdrian Hunter */ 12679e0cc4feSAdrian Hunter u64 rem = (0ULL - mm->len) % mm->len; 12689e0cc4feSAdrian Hunter 12699e0cc4feSAdrian Hunter offset = head - size - rem; 12709e0cc4feSAdrian Hunter } 12719e0cc4feSAdrian Hunter 12729e0cc4feSAdrian Hunter if (size > head_off) { 12739e0cc4feSAdrian Hunter len1 = size - head_off; 12749e0cc4feSAdrian Hunter data1 = &data[mm->len - len1]; 12759e0cc4feSAdrian Hunter len2 = head_off; 12769e0cc4feSAdrian Hunter data2 = &data[0]; 12779e0cc4feSAdrian Hunter } else { 12789e0cc4feSAdrian Hunter len1 = size; 12799e0cc4feSAdrian Hunter data1 = &data[head_off - len1]; 12809e0cc4feSAdrian Hunter len2 = 0; 12819e0cc4feSAdrian Hunter data2 = NULL; 12829e0cc4feSAdrian Hunter } 12839e0cc4feSAdrian Hunter 128483b2ea25SAdrian Hunter if (itr->alignment) { 128583b2ea25SAdrian Hunter unsigned int unwanted = len1 % itr->alignment; 128683b2ea25SAdrian Hunter 128783b2ea25SAdrian Hunter len1 -= unwanted; 128883b2ea25SAdrian Hunter size -= unwanted; 128983b2ea25SAdrian Hunter } 129083b2ea25SAdrian Hunter 12919e0cc4feSAdrian Hunter /* padding must be written by fn() e.g. record__process_auxtrace() */ 1292c3fcadf0SAdrian Hunter padding = size & (PERF_AUXTRACE_RECORD_ALIGNMENT - 1); 12939e0cc4feSAdrian Hunter if (padding) 1294c3fcadf0SAdrian Hunter padding = PERF_AUXTRACE_RECORD_ALIGNMENT - padding; 12959e0cc4feSAdrian Hunter 12969e0cc4feSAdrian Hunter memset(&ev, 0, sizeof(ev)); 12979e0cc4feSAdrian Hunter ev.auxtrace.header.type = PERF_RECORD_AUXTRACE; 12989e0cc4feSAdrian Hunter ev.auxtrace.header.size = sizeof(ev.auxtrace); 12999e0cc4feSAdrian Hunter ev.auxtrace.size = size + padding; 13009e0cc4feSAdrian Hunter ev.auxtrace.offset = offset; 13019e0cc4feSAdrian Hunter ev.auxtrace.reference = ref; 13029e0cc4feSAdrian Hunter ev.auxtrace.idx = mm->idx; 13039e0cc4feSAdrian Hunter ev.auxtrace.tid = mm->tid; 13049e0cc4feSAdrian Hunter ev.auxtrace.cpu = mm->cpu; 13059e0cc4feSAdrian Hunter 1306ded2b8feSJiri Olsa if (fn(tool, map, &ev, data1, len1, data2, len2)) 13079e0cc4feSAdrian Hunter return -1; 13089e0cc4feSAdrian Hunter 13099e0cc4feSAdrian Hunter mm->prev = head; 13109e0cc4feSAdrian Hunter 1311d20031bbSAdrian Hunter if (!snapshot) { 13129e0cc4feSAdrian Hunter auxtrace_mmap__write_tail(mm, head); 13139e0cc4feSAdrian Hunter if (itr->read_finish) { 13149e0cc4feSAdrian Hunter int err; 13159e0cc4feSAdrian Hunter 13169e0cc4feSAdrian Hunter err = itr->read_finish(itr, mm->idx); 13179e0cc4feSAdrian Hunter if (err < 0) 13189e0cc4feSAdrian Hunter return err; 13199e0cc4feSAdrian Hunter } 1320d20031bbSAdrian Hunter } 13219e0cc4feSAdrian Hunter 13229e0cc4feSAdrian Hunter return 1; 13239e0cc4feSAdrian Hunter } 1324c3278f02SAdrian Hunter 1325e035f4caSJiri Olsa int auxtrace_mmap__read(struct perf_mmap *map, struct auxtrace_record *itr, 1326d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn) 1327d20031bbSAdrian Hunter { 1328e035f4caSJiri Olsa return __auxtrace_mmap__read(map, itr, tool, fn, false, 0); 1329d20031bbSAdrian Hunter } 1330d20031bbSAdrian Hunter 1331e035f4caSJiri Olsa int auxtrace_mmap__read_snapshot(struct perf_mmap *map, 1332d20031bbSAdrian Hunter struct auxtrace_record *itr, 1333d20031bbSAdrian Hunter struct perf_tool *tool, process_auxtrace_t fn, 1334d20031bbSAdrian Hunter size_t snapshot_size) 1335d20031bbSAdrian Hunter { 1336e035f4caSJiri Olsa return __auxtrace_mmap__read(map, itr, tool, fn, true, snapshot_size); 1337d20031bbSAdrian Hunter } 1338d20031bbSAdrian Hunter 1339c3278f02SAdrian Hunter /** 1340c3278f02SAdrian Hunter * struct auxtrace_cache - hash table to implement a cache 1341c3278f02SAdrian Hunter * @hashtable: the hashtable 1342c3278f02SAdrian Hunter * @sz: hashtable size (number of hlists) 1343c3278f02SAdrian Hunter * @entry_size: size of an entry 1344c3278f02SAdrian Hunter * @limit: limit the number of entries to this maximum, when reached the cache 1345c3278f02SAdrian Hunter * is dropped and caching begins again with an empty cache 1346c3278f02SAdrian Hunter * @cnt: current number of entries 1347c3278f02SAdrian Hunter * @bits: hashtable size (@sz = 2^@bits) 1348c3278f02SAdrian Hunter */ 1349c3278f02SAdrian Hunter struct auxtrace_cache { 1350c3278f02SAdrian Hunter struct hlist_head *hashtable; 1351c3278f02SAdrian Hunter size_t sz; 1352c3278f02SAdrian Hunter size_t entry_size; 1353c3278f02SAdrian Hunter size_t limit; 1354c3278f02SAdrian Hunter size_t cnt; 1355c3278f02SAdrian Hunter unsigned int bits; 1356c3278f02SAdrian Hunter }; 1357c3278f02SAdrian Hunter 1358c3278f02SAdrian Hunter struct auxtrace_cache *auxtrace_cache__new(unsigned int bits, size_t entry_size, 1359c3278f02SAdrian Hunter unsigned int limit_percent) 1360c3278f02SAdrian Hunter { 1361c3278f02SAdrian Hunter struct auxtrace_cache *c; 1362c3278f02SAdrian Hunter struct hlist_head *ht; 1363c3278f02SAdrian Hunter size_t sz, i; 1364c3278f02SAdrian Hunter 1365c3278f02SAdrian Hunter c = zalloc(sizeof(struct auxtrace_cache)); 1366c3278f02SAdrian Hunter if (!c) 1367c3278f02SAdrian Hunter return NULL; 1368c3278f02SAdrian Hunter 1369c3278f02SAdrian Hunter sz = 1UL << bits; 1370c3278f02SAdrian Hunter 1371c3278f02SAdrian Hunter ht = calloc(sz, sizeof(struct hlist_head)); 1372c3278f02SAdrian Hunter if (!ht) 1373c3278f02SAdrian Hunter goto out_free; 1374c3278f02SAdrian Hunter 1375c3278f02SAdrian Hunter for (i = 0; i < sz; i++) 1376c3278f02SAdrian Hunter INIT_HLIST_HEAD(&ht[i]); 1377c3278f02SAdrian Hunter 1378c3278f02SAdrian Hunter c->hashtable = ht; 1379c3278f02SAdrian Hunter c->sz = sz; 1380c3278f02SAdrian Hunter c->entry_size = entry_size; 1381c3278f02SAdrian Hunter c->limit = (c->sz * limit_percent) / 100; 1382c3278f02SAdrian Hunter c->bits = bits; 1383c3278f02SAdrian Hunter 1384c3278f02SAdrian Hunter return c; 1385c3278f02SAdrian Hunter 1386c3278f02SAdrian Hunter out_free: 1387c3278f02SAdrian Hunter free(c); 1388c3278f02SAdrian Hunter return NULL; 1389c3278f02SAdrian Hunter } 1390c3278f02SAdrian Hunter 1391c3278f02SAdrian Hunter static void auxtrace_cache__drop(struct auxtrace_cache *c) 1392c3278f02SAdrian Hunter { 1393c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry; 1394c3278f02SAdrian Hunter struct hlist_node *tmp; 1395c3278f02SAdrian Hunter size_t i; 1396c3278f02SAdrian Hunter 1397c3278f02SAdrian Hunter if (!c) 1398c3278f02SAdrian Hunter return; 1399c3278f02SAdrian Hunter 1400c3278f02SAdrian Hunter for (i = 0; i < c->sz; i++) { 1401c3278f02SAdrian Hunter hlist_for_each_entry_safe(entry, tmp, &c->hashtable[i], hash) { 1402c3278f02SAdrian Hunter hlist_del(&entry->hash); 1403c3278f02SAdrian Hunter auxtrace_cache__free_entry(c, entry); 1404c3278f02SAdrian Hunter } 1405c3278f02SAdrian Hunter } 1406c3278f02SAdrian Hunter 1407c3278f02SAdrian Hunter c->cnt = 0; 1408c3278f02SAdrian Hunter } 1409c3278f02SAdrian Hunter 1410c3278f02SAdrian Hunter void auxtrace_cache__free(struct auxtrace_cache *c) 1411c3278f02SAdrian Hunter { 1412c3278f02SAdrian Hunter if (!c) 1413c3278f02SAdrian Hunter return; 1414c3278f02SAdrian Hunter 1415c3278f02SAdrian Hunter auxtrace_cache__drop(c); 1416*d8f9da24SArnaldo Carvalho de Melo zfree(&c->hashtable); 1417c3278f02SAdrian Hunter free(c); 1418c3278f02SAdrian Hunter } 1419c3278f02SAdrian Hunter 1420c3278f02SAdrian Hunter void *auxtrace_cache__alloc_entry(struct auxtrace_cache *c) 1421c3278f02SAdrian Hunter { 1422c3278f02SAdrian Hunter return malloc(c->entry_size); 1423c3278f02SAdrian Hunter } 1424c3278f02SAdrian Hunter 1425c3278f02SAdrian Hunter void auxtrace_cache__free_entry(struct auxtrace_cache *c __maybe_unused, 1426c3278f02SAdrian Hunter void *entry) 1427c3278f02SAdrian Hunter { 1428c3278f02SAdrian Hunter free(entry); 1429c3278f02SAdrian Hunter } 1430c3278f02SAdrian Hunter 1431c3278f02SAdrian Hunter int auxtrace_cache__add(struct auxtrace_cache *c, u32 key, 1432c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry) 1433c3278f02SAdrian Hunter { 1434c3278f02SAdrian Hunter if (c->limit && ++c->cnt > c->limit) 1435c3278f02SAdrian Hunter auxtrace_cache__drop(c); 1436c3278f02SAdrian Hunter 1437c3278f02SAdrian Hunter entry->key = key; 1438c3278f02SAdrian Hunter hlist_add_head(&entry->hash, &c->hashtable[hash_32(key, c->bits)]); 1439c3278f02SAdrian Hunter 1440c3278f02SAdrian Hunter return 0; 1441c3278f02SAdrian Hunter } 1442c3278f02SAdrian Hunter 1443c3278f02SAdrian Hunter void *auxtrace_cache__lookup(struct auxtrace_cache *c, u32 key) 1444c3278f02SAdrian Hunter { 1445c3278f02SAdrian Hunter struct auxtrace_cache_entry *entry; 1446c3278f02SAdrian Hunter struct hlist_head *hlist; 1447c3278f02SAdrian Hunter 1448c3278f02SAdrian Hunter if (!c) 1449c3278f02SAdrian Hunter return NULL; 1450c3278f02SAdrian Hunter 1451c3278f02SAdrian Hunter hlist = &c->hashtable[hash_32(key, c->bits)]; 1452c3278f02SAdrian Hunter hlist_for_each_entry(entry, hlist, hash) { 1453c3278f02SAdrian Hunter if (entry->key == key) 1454c3278f02SAdrian Hunter return entry; 1455c3278f02SAdrian Hunter } 1456c3278f02SAdrian Hunter 1457c3278f02SAdrian Hunter return NULL; 1458c3278f02SAdrian Hunter } 14591b36c03eSAdrian Hunter 14601b36c03eSAdrian Hunter static void addr_filter__free_str(struct addr_filter *filt) 14611b36c03eSAdrian Hunter { 1462*d8f9da24SArnaldo Carvalho de Melo zfree(&filt->str); 14631b36c03eSAdrian Hunter filt->action = NULL; 14641b36c03eSAdrian Hunter filt->sym_from = NULL; 14651b36c03eSAdrian Hunter filt->sym_to = NULL; 14661b36c03eSAdrian Hunter filt->filename = NULL; 14671b36c03eSAdrian Hunter } 14681b36c03eSAdrian Hunter 14691b36c03eSAdrian Hunter static struct addr_filter *addr_filter__new(void) 14701b36c03eSAdrian Hunter { 14711b36c03eSAdrian Hunter struct addr_filter *filt = zalloc(sizeof(*filt)); 14721b36c03eSAdrian Hunter 14731b36c03eSAdrian Hunter if (filt) 14741b36c03eSAdrian Hunter INIT_LIST_HEAD(&filt->list); 14751b36c03eSAdrian Hunter 14761b36c03eSAdrian Hunter return filt; 14771b36c03eSAdrian Hunter } 14781b36c03eSAdrian Hunter 14791b36c03eSAdrian Hunter static void addr_filter__free(struct addr_filter *filt) 14801b36c03eSAdrian Hunter { 14811b36c03eSAdrian Hunter if (filt) 14821b36c03eSAdrian Hunter addr_filter__free_str(filt); 14831b36c03eSAdrian Hunter free(filt); 14841b36c03eSAdrian Hunter } 14851b36c03eSAdrian Hunter 14861b36c03eSAdrian Hunter static void addr_filters__add(struct addr_filters *filts, 14871b36c03eSAdrian Hunter struct addr_filter *filt) 14881b36c03eSAdrian Hunter { 14891b36c03eSAdrian Hunter list_add_tail(&filt->list, &filts->head); 14901b36c03eSAdrian Hunter filts->cnt += 1; 14911b36c03eSAdrian Hunter } 14921b36c03eSAdrian Hunter 14931b36c03eSAdrian Hunter static void addr_filters__del(struct addr_filters *filts, 14941b36c03eSAdrian Hunter struct addr_filter *filt) 14951b36c03eSAdrian Hunter { 14961b36c03eSAdrian Hunter list_del_init(&filt->list); 14971b36c03eSAdrian Hunter filts->cnt -= 1; 14981b36c03eSAdrian Hunter } 14991b36c03eSAdrian Hunter 15001b36c03eSAdrian Hunter void addr_filters__init(struct addr_filters *filts) 15011b36c03eSAdrian Hunter { 15021b36c03eSAdrian Hunter INIT_LIST_HEAD(&filts->head); 15031b36c03eSAdrian Hunter filts->cnt = 0; 15041b36c03eSAdrian Hunter } 15051b36c03eSAdrian Hunter 15061b36c03eSAdrian Hunter void addr_filters__exit(struct addr_filters *filts) 15071b36c03eSAdrian Hunter { 15081b36c03eSAdrian Hunter struct addr_filter *filt, *n; 15091b36c03eSAdrian Hunter 15101b36c03eSAdrian Hunter list_for_each_entry_safe(filt, n, &filts->head, list) { 15111b36c03eSAdrian Hunter addr_filters__del(filts, filt); 15121b36c03eSAdrian Hunter addr_filter__free(filt); 15131b36c03eSAdrian Hunter } 15141b36c03eSAdrian Hunter } 15151b36c03eSAdrian Hunter 15161b36c03eSAdrian Hunter static int parse_num_or_str(char **inp, u64 *num, const char **str, 15171b36c03eSAdrian Hunter const char *str_delim) 15181b36c03eSAdrian Hunter { 15191b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 15201b36c03eSAdrian Hunter 15211b36c03eSAdrian Hunter if (isdigit(**inp)) { 15221b36c03eSAdrian Hunter char *endptr; 15231b36c03eSAdrian Hunter 15241b36c03eSAdrian Hunter if (!num) 15251b36c03eSAdrian Hunter return -EINVAL; 15261b36c03eSAdrian Hunter errno = 0; 15271b36c03eSAdrian Hunter *num = strtoull(*inp, &endptr, 0); 15281b36c03eSAdrian Hunter if (errno) 15291b36c03eSAdrian Hunter return -errno; 15301b36c03eSAdrian Hunter if (endptr == *inp) 15311b36c03eSAdrian Hunter return -EINVAL; 15321b36c03eSAdrian Hunter *inp = endptr; 15331b36c03eSAdrian Hunter } else { 15341b36c03eSAdrian Hunter size_t n; 15351b36c03eSAdrian Hunter 15361b36c03eSAdrian Hunter if (!str) 15371b36c03eSAdrian Hunter return -EINVAL; 15381b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 15391b36c03eSAdrian Hunter *str = *inp; 15401b36c03eSAdrian Hunter n = strcspn(*inp, str_delim); 15411b36c03eSAdrian Hunter if (!n) 15421b36c03eSAdrian Hunter return -EINVAL; 15431b36c03eSAdrian Hunter *inp += n; 15441b36c03eSAdrian Hunter if (**inp) { 15451b36c03eSAdrian Hunter **inp = '\0'; 15461b36c03eSAdrian Hunter *inp += 1; 15471b36c03eSAdrian Hunter } 15481b36c03eSAdrian Hunter } 15491b36c03eSAdrian Hunter return 0; 15501b36c03eSAdrian Hunter } 15511b36c03eSAdrian Hunter 15521b36c03eSAdrian Hunter static int parse_action(struct addr_filter *filt) 15531b36c03eSAdrian Hunter { 15541b36c03eSAdrian Hunter if (!strcmp(filt->action, "filter")) { 15551b36c03eSAdrian Hunter filt->start = true; 15561b36c03eSAdrian Hunter filt->range = true; 15571b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "start")) { 15581b36c03eSAdrian Hunter filt->start = true; 15591b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "stop")) { 15601b36c03eSAdrian Hunter filt->start = false; 15611b36c03eSAdrian Hunter } else if (!strcmp(filt->action, "tracestop")) { 15621b36c03eSAdrian Hunter filt->start = false; 15631b36c03eSAdrian Hunter filt->range = true; 15641b36c03eSAdrian Hunter filt->action += 5; /* Change 'tracestop' to 'stop' */ 15651b36c03eSAdrian Hunter } else { 15661b36c03eSAdrian Hunter return -EINVAL; 15671b36c03eSAdrian Hunter } 15681b36c03eSAdrian Hunter return 0; 15691b36c03eSAdrian Hunter } 15701b36c03eSAdrian Hunter 15711b36c03eSAdrian Hunter static int parse_sym_idx(char **inp, int *idx) 15721b36c03eSAdrian Hunter { 15731b36c03eSAdrian Hunter *idx = -1; 15741b36c03eSAdrian Hunter 15751b36c03eSAdrian Hunter *inp += strspn(*inp, " "); 15761b36c03eSAdrian Hunter 15771b36c03eSAdrian Hunter if (**inp != '#') 15781b36c03eSAdrian Hunter return 0; 15791b36c03eSAdrian Hunter 15801b36c03eSAdrian Hunter *inp += 1; 15811b36c03eSAdrian Hunter 15821b36c03eSAdrian Hunter if (**inp == 'g' || **inp == 'G') { 15831b36c03eSAdrian Hunter *inp += 1; 15841b36c03eSAdrian Hunter *idx = 0; 15851b36c03eSAdrian Hunter } else { 15861b36c03eSAdrian Hunter unsigned long num; 15871b36c03eSAdrian Hunter char *endptr; 15881b36c03eSAdrian Hunter 15891b36c03eSAdrian Hunter errno = 0; 15901b36c03eSAdrian Hunter num = strtoul(*inp, &endptr, 0); 15911b36c03eSAdrian Hunter if (errno) 15921b36c03eSAdrian Hunter return -errno; 15931b36c03eSAdrian Hunter if (endptr == *inp || num > INT_MAX) 15941b36c03eSAdrian Hunter return -EINVAL; 15951b36c03eSAdrian Hunter *inp = endptr; 15961b36c03eSAdrian Hunter *idx = num; 15971b36c03eSAdrian Hunter } 15981b36c03eSAdrian Hunter 15991b36c03eSAdrian Hunter return 0; 16001b36c03eSAdrian Hunter } 16011b36c03eSAdrian Hunter 16021b36c03eSAdrian Hunter static int parse_addr_size(char **inp, u64 *num, const char **str, int *idx) 16031b36c03eSAdrian Hunter { 16041b36c03eSAdrian Hunter int err = parse_num_or_str(inp, num, str, " "); 16051b36c03eSAdrian Hunter 16061b36c03eSAdrian Hunter if (!err && *str) 16071b36c03eSAdrian Hunter err = parse_sym_idx(inp, idx); 16081b36c03eSAdrian Hunter 16091b36c03eSAdrian Hunter return err; 16101b36c03eSAdrian Hunter } 16111b36c03eSAdrian Hunter 16121b36c03eSAdrian Hunter static int parse_one_filter(struct addr_filter *filt, const char **filter_inp) 16131b36c03eSAdrian Hunter { 16141b36c03eSAdrian Hunter char *fstr; 16151b36c03eSAdrian Hunter int err; 16161b36c03eSAdrian Hunter 16171b36c03eSAdrian Hunter filt->str = fstr = strdup(*filter_inp); 16181b36c03eSAdrian Hunter if (!fstr) 16191b36c03eSAdrian Hunter return -ENOMEM; 16201b36c03eSAdrian Hunter 16211b36c03eSAdrian Hunter err = parse_num_or_str(&fstr, NULL, &filt->action, " "); 16221b36c03eSAdrian Hunter if (err) 16231b36c03eSAdrian Hunter goto out_err; 16241b36c03eSAdrian Hunter 16251b36c03eSAdrian Hunter err = parse_action(filt); 16261b36c03eSAdrian Hunter if (err) 16271b36c03eSAdrian Hunter goto out_err; 16281b36c03eSAdrian Hunter 16291b36c03eSAdrian Hunter err = parse_addr_size(&fstr, &filt->addr, &filt->sym_from, 16301b36c03eSAdrian Hunter &filt->sym_from_idx); 16311b36c03eSAdrian Hunter if (err) 16321b36c03eSAdrian Hunter goto out_err; 16331b36c03eSAdrian Hunter 16341b36c03eSAdrian Hunter fstr += strspn(fstr, " "); 16351b36c03eSAdrian Hunter 16361b36c03eSAdrian Hunter if (*fstr == '/') { 16371b36c03eSAdrian Hunter fstr += 1; 16381b36c03eSAdrian Hunter err = parse_addr_size(&fstr, &filt->size, &filt->sym_to, 16391b36c03eSAdrian Hunter &filt->sym_to_idx); 16401b36c03eSAdrian Hunter if (err) 16411b36c03eSAdrian Hunter goto out_err; 16421b36c03eSAdrian Hunter filt->range = true; 16431b36c03eSAdrian Hunter } 16441b36c03eSAdrian Hunter 16451b36c03eSAdrian Hunter fstr += strspn(fstr, " "); 16461b36c03eSAdrian Hunter 16471b36c03eSAdrian Hunter if (*fstr == '@') { 16481b36c03eSAdrian Hunter fstr += 1; 16491b36c03eSAdrian Hunter err = parse_num_or_str(&fstr, NULL, &filt->filename, " ,"); 16501b36c03eSAdrian Hunter if (err) 16511b36c03eSAdrian Hunter goto out_err; 16521b36c03eSAdrian Hunter } 16531b36c03eSAdrian Hunter 16541b36c03eSAdrian Hunter fstr += strspn(fstr, " ,"); 16551b36c03eSAdrian Hunter 16561b36c03eSAdrian Hunter *filter_inp += fstr - filt->str; 16571b36c03eSAdrian Hunter 16581b36c03eSAdrian Hunter return 0; 16591b36c03eSAdrian Hunter 16601b36c03eSAdrian Hunter out_err: 16611b36c03eSAdrian Hunter addr_filter__free_str(filt); 16621b36c03eSAdrian Hunter 16631b36c03eSAdrian Hunter return err; 16641b36c03eSAdrian Hunter } 16651b36c03eSAdrian Hunter 16661b36c03eSAdrian Hunter int addr_filters__parse_bare_filter(struct addr_filters *filts, 16671b36c03eSAdrian Hunter const char *filter) 16681b36c03eSAdrian Hunter { 16691b36c03eSAdrian Hunter struct addr_filter *filt; 16701b36c03eSAdrian Hunter const char *fstr = filter; 16711b36c03eSAdrian Hunter int err; 16721b36c03eSAdrian Hunter 16731b36c03eSAdrian Hunter while (*fstr) { 16741b36c03eSAdrian Hunter filt = addr_filter__new(); 16751b36c03eSAdrian Hunter err = parse_one_filter(filt, &fstr); 16761b36c03eSAdrian Hunter if (err) { 16771b36c03eSAdrian Hunter addr_filter__free(filt); 16781b36c03eSAdrian Hunter addr_filters__exit(filts); 16791b36c03eSAdrian Hunter return err; 16801b36c03eSAdrian Hunter } 16811b36c03eSAdrian Hunter addr_filters__add(filts, filt); 16821b36c03eSAdrian Hunter } 16831b36c03eSAdrian Hunter 16841b36c03eSAdrian Hunter return 0; 16851b36c03eSAdrian Hunter } 16861b36c03eSAdrian Hunter 16871b36c03eSAdrian Hunter struct sym_args { 16881b36c03eSAdrian Hunter const char *name; 16891b36c03eSAdrian Hunter u64 start; 16901b36c03eSAdrian Hunter u64 size; 16911b36c03eSAdrian Hunter int idx; 16921b36c03eSAdrian Hunter int cnt; 16931b36c03eSAdrian Hunter bool started; 16941b36c03eSAdrian Hunter bool global; 16951b36c03eSAdrian Hunter bool selected; 16961b36c03eSAdrian Hunter bool duplicate; 16971b36c03eSAdrian Hunter bool near; 16981b36c03eSAdrian Hunter }; 16991b36c03eSAdrian Hunter 17001b36c03eSAdrian Hunter static bool kern_sym_match(struct sym_args *args, const char *name, char type) 17011b36c03eSAdrian Hunter { 17021b36c03eSAdrian Hunter /* A function with the same name, and global or the n'th found or any */ 1703e85e0e0cSArnaldo Carvalho de Melo return kallsyms__is_function(type) && 17041b36c03eSAdrian Hunter !strcmp(name, args->name) && 17051b36c03eSAdrian Hunter ((args->global && isupper(type)) || 17061b36c03eSAdrian Hunter (args->selected && ++(args->cnt) == args->idx) || 17071b36c03eSAdrian Hunter (!args->global && !args->selected)); 17081b36c03eSAdrian Hunter } 17091b36c03eSAdrian Hunter 17101b36c03eSAdrian Hunter static int find_kern_sym_cb(void *arg, const char *name, char type, u64 start) 17111b36c03eSAdrian Hunter { 17121b36c03eSAdrian Hunter struct sym_args *args = arg; 17131b36c03eSAdrian Hunter 17141b36c03eSAdrian Hunter if (args->started) { 17151b36c03eSAdrian Hunter if (!args->size) 17161b36c03eSAdrian Hunter args->size = start - args->start; 17171b36c03eSAdrian Hunter if (args->selected) { 17181b36c03eSAdrian Hunter if (args->size) 17191b36c03eSAdrian Hunter return 1; 17201b36c03eSAdrian Hunter } else if (kern_sym_match(args, name, type)) { 17211b36c03eSAdrian Hunter args->duplicate = true; 17221b36c03eSAdrian Hunter return 1; 17231b36c03eSAdrian Hunter } 17241b36c03eSAdrian Hunter } else if (kern_sym_match(args, name, type)) { 17251b36c03eSAdrian Hunter args->started = true; 17261b36c03eSAdrian Hunter args->start = start; 17271b36c03eSAdrian Hunter } 17281b36c03eSAdrian Hunter 17291b36c03eSAdrian Hunter return 0; 17301b36c03eSAdrian Hunter } 17311b36c03eSAdrian Hunter 17321b36c03eSAdrian Hunter static int print_kern_sym_cb(void *arg, const char *name, char type, u64 start) 17331b36c03eSAdrian Hunter { 17341b36c03eSAdrian Hunter struct sym_args *args = arg; 17351b36c03eSAdrian Hunter 17361b36c03eSAdrian Hunter if (kern_sym_match(args, name, type)) { 17371b36c03eSAdrian Hunter pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 17381b36c03eSAdrian Hunter ++args->cnt, start, type, name); 17391b36c03eSAdrian Hunter args->near = true; 17401b36c03eSAdrian Hunter } else if (args->near) { 17411b36c03eSAdrian Hunter args->near = false; 17421b36c03eSAdrian Hunter pr_err("\t\twhich is near\t\t%s\n", name); 17431b36c03eSAdrian Hunter } 17441b36c03eSAdrian Hunter 17451b36c03eSAdrian Hunter return 0; 17461b36c03eSAdrian Hunter } 17471b36c03eSAdrian Hunter 17481b36c03eSAdrian Hunter static int sym_not_found_error(const char *sym_name, int idx) 17491b36c03eSAdrian Hunter { 17501b36c03eSAdrian Hunter if (idx > 0) { 17511b36c03eSAdrian Hunter pr_err("N'th occurrence (N=%d) of symbol '%s' not found.\n", 17521b36c03eSAdrian Hunter idx, sym_name); 17531b36c03eSAdrian Hunter } else if (!idx) { 17541b36c03eSAdrian Hunter pr_err("Global symbol '%s' not found.\n", sym_name); 17551b36c03eSAdrian Hunter } else { 17561b36c03eSAdrian Hunter pr_err("Symbol '%s' not found.\n", sym_name); 17571b36c03eSAdrian Hunter } 17581b36c03eSAdrian Hunter pr_err("Note that symbols must be functions.\n"); 17591b36c03eSAdrian Hunter 17601b36c03eSAdrian Hunter return -EINVAL; 17611b36c03eSAdrian Hunter } 17621b36c03eSAdrian Hunter 17631b36c03eSAdrian Hunter static int find_kern_sym(const char *sym_name, u64 *start, u64 *size, int idx) 17641b36c03eSAdrian Hunter { 17651b36c03eSAdrian Hunter struct sym_args args = { 17661b36c03eSAdrian Hunter .name = sym_name, 17671b36c03eSAdrian Hunter .idx = idx, 17681b36c03eSAdrian Hunter .global = !idx, 17691b36c03eSAdrian Hunter .selected = idx > 0, 17701b36c03eSAdrian Hunter }; 17711b36c03eSAdrian Hunter int err; 17721b36c03eSAdrian Hunter 17731b36c03eSAdrian Hunter *start = 0; 17741b36c03eSAdrian Hunter *size = 0; 17751b36c03eSAdrian Hunter 17761b36c03eSAdrian Hunter err = kallsyms__parse("/proc/kallsyms", &args, find_kern_sym_cb); 17771b36c03eSAdrian Hunter if (err < 0) { 17781b36c03eSAdrian Hunter pr_err("Failed to parse /proc/kallsyms\n"); 17791b36c03eSAdrian Hunter return err; 17801b36c03eSAdrian Hunter } 17811b36c03eSAdrian Hunter 17821b36c03eSAdrian Hunter if (args.duplicate) { 17831b36c03eSAdrian Hunter pr_err("Multiple kernel symbols with name '%s'\n", sym_name); 17841b36c03eSAdrian Hunter args.cnt = 0; 17851b36c03eSAdrian Hunter kallsyms__parse("/proc/kallsyms", &args, print_kern_sym_cb); 17861b36c03eSAdrian Hunter pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 17871b36c03eSAdrian Hunter sym_name); 17881b36c03eSAdrian Hunter pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 17891b36c03eSAdrian Hunter return -EINVAL; 17901b36c03eSAdrian Hunter } 17911b36c03eSAdrian Hunter 17921b36c03eSAdrian Hunter if (!args.started) { 17931b36c03eSAdrian Hunter pr_err("Kernel symbol lookup: "); 17941b36c03eSAdrian Hunter return sym_not_found_error(sym_name, idx); 17951b36c03eSAdrian Hunter } 17961b36c03eSAdrian Hunter 17971b36c03eSAdrian Hunter *start = args.start; 17981b36c03eSAdrian Hunter *size = args.size; 17991b36c03eSAdrian Hunter 18001b36c03eSAdrian Hunter return 0; 18011b36c03eSAdrian Hunter } 18021b36c03eSAdrian Hunter 18031b36c03eSAdrian Hunter static int find_entire_kern_cb(void *arg, const char *name __maybe_unused, 18041b36c03eSAdrian Hunter char type, u64 start) 18051b36c03eSAdrian Hunter { 18061b36c03eSAdrian Hunter struct sym_args *args = arg; 18071b36c03eSAdrian Hunter 1808e85e0e0cSArnaldo Carvalho de Melo if (!kallsyms__is_function(type)) 18091b36c03eSAdrian Hunter return 0; 18101b36c03eSAdrian Hunter 18111b36c03eSAdrian Hunter if (!args->started) { 18121b36c03eSAdrian Hunter args->started = true; 18131b36c03eSAdrian Hunter args->start = start; 18141b36c03eSAdrian Hunter } 18151b36c03eSAdrian Hunter /* Don't know exactly where the kernel ends, so we add a page */ 18161b36c03eSAdrian Hunter args->size = round_up(start, page_size) + page_size - args->start; 18171b36c03eSAdrian Hunter 18181b36c03eSAdrian Hunter return 0; 18191b36c03eSAdrian Hunter } 18201b36c03eSAdrian Hunter 18211b36c03eSAdrian Hunter static int addr_filter__entire_kernel(struct addr_filter *filt) 18221b36c03eSAdrian Hunter { 18231b36c03eSAdrian Hunter struct sym_args args = { .started = false }; 18241b36c03eSAdrian Hunter int err; 18251b36c03eSAdrian Hunter 18261b36c03eSAdrian Hunter err = kallsyms__parse("/proc/kallsyms", &args, find_entire_kern_cb); 18271b36c03eSAdrian Hunter if (err < 0 || !args.started) { 18281b36c03eSAdrian Hunter pr_err("Failed to parse /proc/kallsyms\n"); 18291b36c03eSAdrian Hunter return err; 18301b36c03eSAdrian Hunter } 18311b36c03eSAdrian Hunter 18321b36c03eSAdrian Hunter filt->addr = args.start; 18331b36c03eSAdrian Hunter filt->size = args.size; 18341b36c03eSAdrian Hunter 18351b36c03eSAdrian Hunter return 0; 18361b36c03eSAdrian Hunter } 18371b36c03eSAdrian Hunter 18381b36c03eSAdrian Hunter static int check_end_after_start(struct addr_filter *filt, u64 start, u64 size) 18391b36c03eSAdrian Hunter { 18401b36c03eSAdrian Hunter if (start + size >= filt->addr) 18411b36c03eSAdrian Hunter return 0; 18421b36c03eSAdrian Hunter 18431b36c03eSAdrian Hunter if (filt->sym_from) { 18441b36c03eSAdrian Hunter pr_err("Symbol '%s' (0x%"PRIx64") comes before '%s' (0x%"PRIx64")\n", 18451b36c03eSAdrian Hunter filt->sym_to, start, filt->sym_from, filt->addr); 18461b36c03eSAdrian Hunter } else { 18471b36c03eSAdrian Hunter pr_err("Symbol '%s' (0x%"PRIx64") comes before address 0x%"PRIx64")\n", 18481b36c03eSAdrian Hunter filt->sym_to, start, filt->addr); 18491b36c03eSAdrian Hunter } 18501b36c03eSAdrian Hunter 18511b36c03eSAdrian Hunter return -EINVAL; 18521b36c03eSAdrian Hunter } 18531b36c03eSAdrian Hunter 18541b36c03eSAdrian Hunter static int addr_filter__resolve_kernel_syms(struct addr_filter *filt) 18551b36c03eSAdrian Hunter { 18561b36c03eSAdrian Hunter bool no_size = false; 18571b36c03eSAdrian Hunter u64 start, size; 18581b36c03eSAdrian Hunter int err; 18591b36c03eSAdrian Hunter 18601b36c03eSAdrian Hunter if (symbol_conf.kptr_restrict) { 18611b36c03eSAdrian Hunter pr_err("Kernel addresses are restricted. Unable to resolve kernel symbols.\n"); 18621b36c03eSAdrian Hunter return -EINVAL; 18631b36c03eSAdrian Hunter } 18641b36c03eSAdrian Hunter 18651b36c03eSAdrian Hunter if (filt->sym_from && !strcmp(filt->sym_from, "*")) 18661b36c03eSAdrian Hunter return addr_filter__entire_kernel(filt); 18671b36c03eSAdrian Hunter 18681b36c03eSAdrian Hunter if (filt->sym_from) { 18691b36c03eSAdrian Hunter err = find_kern_sym(filt->sym_from, &start, &size, 18701b36c03eSAdrian Hunter filt->sym_from_idx); 18711b36c03eSAdrian Hunter if (err) 18721b36c03eSAdrian Hunter return err; 18731b36c03eSAdrian Hunter filt->addr = start; 18741b36c03eSAdrian Hunter if (filt->range && !filt->size && !filt->sym_to) { 18751b36c03eSAdrian Hunter filt->size = size; 1876c3a0bbc7SAdrian Hunter no_size = !size; 18771b36c03eSAdrian Hunter } 18781b36c03eSAdrian Hunter } 18791b36c03eSAdrian Hunter 18801b36c03eSAdrian Hunter if (filt->sym_to) { 18811b36c03eSAdrian Hunter err = find_kern_sym(filt->sym_to, &start, &size, 18821b36c03eSAdrian Hunter filt->sym_to_idx); 18831b36c03eSAdrian Hunter if (err) 18841b36c03eSAdrian Hunter return err; 18851b36c03eSAdrian Hunter 18861b36c03eSAdrian Hunter err = check_end_after_start(filt, start, size); 18871b36c03eSAdrian Hunter if (err) 18881b36c03eSAdrian Hunter return err; 18891b36c03eSAdrian Hunter filt->size = start + size - filt->addr; 1890c3a0bbc7SAdrian Hunter no_size = !size; 18911b36c03eSAdrian Hunter } 18921b36c03eSAdrian Hunter 18931b36c03eSAdrian Hunter /* The very last symbol in kallsyms does not imply a particular size */ 18941b36c03eSAdrian Hunter if (no_size) { 18951b36c03eSAdrian Hunter pr_err("Cannot determine size of symbol '%s'\n", 18961b36c03eSAdrian Hunter filt->sym_to ? filt->sym_to : filt->sym_from); 18971b36c03eSAdrian Hunter return -EINVAL; 18981b36c03eSAdrian Hunter } 18991b36c03eSAdrian Hunter 19001b36c03eSAdrian Hunter return 0; 19011b36c03eSAdrian Hunter } 19021b36c03eSAdrian Hunter 19031b36c03eSAdrian Hunter static struct dso *load_dso(const char *name) 19041b36c03eSAdrian Hunter { 19051b36c03eSAdrian Hunter struct map *map; 19061b36c03eSAdrian Hunter struct dso *dso; 19071b36c03eSAdrian Hunter 19081b36c03eSAdrian Hunter map = dso__new_map(name); 19091b36c03eSAdrian Hunter if (!map) 19101b36c03eSAdrian Hunter return NULL; 19111b36c03eSAdrian Hunter 1912c1c49204SAdrian Hunter if (map__load(map) < 0) 1913c1c49204SAdrian Hunter pr_err("File '%s' not found or has no symbols.\n", name); 19141b36c03eSAdrian Hunter 19151b36c03eSAdrian Hunter dso = dso__get(map->dso); 19161b36c03eSAdrian Hunter 19171b36c03eSAdrian Hunter map__put(map); 19181b36c03eSAdrian Hunter 19191b36c03eSAdrian Hunter return dso; 19201b36c03eSAdrian Hunter } 19211b36c03eSAdrian Hunter 19221b36c03eSAdrian Hunter static bool dso_sym_match(struct symbol *sym, const char *name, int *cnt, 19231b36c03eSAdrian Hunter int idx) 19241b36c03eSAdrian Hunter { 19251b36c03eSAdrian Hunter /* Same name, and global or the n'th found or any */ 19261b36c03eSAdrian Hunter return !arch__compare_symbol_names(name, sym->name) && 19271b36c03eSAdrian Hunter ((!idx && sym->binding == STB_GLOBAL) || 19281b36c03eSAdrian Hunter (idx > 0 && ++*cnt == idx) || 19291b36c03eSAdrian Hunter idx < 0); 19301b36c03eSAdrian Hunter } 19311b36c03eSAdrian Hunter 19321b36c03eSAdrian Hunter static void print_duplicate_syms(struct dso *dso, const char *sym_name) 19331b36c03eSAdrian Hunter { 19341b36c03eSAdrian Hunter struct symbol *sym; 19351b36c03eSAdrian Hunter bool near = false; 19361b36c03eSAdrian Hunter int cnt = 0; 19371b36c03eSAdrian Hunter 19381b36c03eSAdrian Hunter pr_err("Multiple symbols with name '%s'\n", sym_name); 19391b36c03eSAdrian Hunter 19405cf88a63SArnaldo Carvalho de Melo sym = dso__first_symbol(dso); 19411b36c03eSAdrian Hunter while (sym) { 19421b36c03eSAdrian Hunter if (dso_sym_match(sym, sym_name, &cnt, -1)) { 19431b36c03eSAdrian Hunter pr_err("#%d\t0x%"PRIx64"\t%c\t%s\n", 19441b36c03eSAdrian Hunter ++cnt, sym->start, 19451b36c03eSAdrian Hunter sym->binding == STB_GLOBAL ? 'g' : 19461b36c03eSAdrian Hunter sym->binding == STB_LOCAL ? 'l' : 'w', 19471b36c03eSAdrian Hunter sym->name); 19481b36c03eSAdrian Hunter near = true; 19491b36c03eSAdrian Hunter } else if (near) { 19501b36c03eSAdrian Hunter near = false; 19511b36c03eSAdrian Hunter pr_err("\t\twhich is near\t\t%s\n", sym->name); 19521b36c03eSAdrian Hunter } 19531b36c03eSAdrian Hunter sym = dso__next_symbol(sym); 19541b36c03eSAdrian Hunter } 19551b36c03eSAdrian Hunter 19561b36c03eSAdrian Hunter pr_err("Disambiguate symbol name by inserting #n after the name e.g. %s #2\n", 19571b36c03eSAdrian Hunter sym_name); 19581b36c03eSAdrian Hunter pr_err("Or select a global symbol by inserting #0 or #g or #G\n"); 19591b36c03eSAdrian Hunter } 19601b36c03eSAdrian Hunter 19611b36c03eSAdrian Hunter static int find_dso_sym(struct dso *dso, const char *sym_name, u64 *start, 19621b36c03eSAdrian Hunter u64 *size, int idx) 19631b36c03eSAdrian Hunter { 19641b36c03eSAdrian Hunter struct symbol *sym; 19651b36c03eSAdrian Hunter int cnt = 0; 19661b36c03eSAdrian Hunter 19671b36c03eSAdrian Hunter *start = 0; 19681b36c03eSAdrian Hunter *size = 0; 19691b36c03eSAdrian Hunter 19705cf88a63SArnaldo Carvalho de Melo sym = dso__first_symbol(dso); 19711b36c03eSAdrian Hunter while (sym) { 19721b36c03eSAdrian Hunter if (*start) { 19731b36c03eSAdrian Hunter if (!*size) 19741b36c03eSAdrian Hunter *size = sym->start - *start; 19751b36c03eSAdrian Hunter if (idx > 0) { 19761b36c03eSAdrian Hunter if (*size) 19771b36c03eSAdrian Hunter return 1; 19781b36c03eSAdrian Hunter } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 19791b36c03eSAdrian Hunter print_duplicate_syms(dso, sym_name); 19801b36c03eSAdrian Hunter return -EINVAL; 19811b36c03eSAdrian Hunter } 19821b36c03eSAdrian Hunter } else if (dso_sym_match(sym, sym_name, &cnt, idx)) { 19831b36c03eSAdrian Hunter *start = sym->start; 19841b36c03eSAdrian Hunter *size = sym->end - sym->start; 19851b36c03eSAdrian Hunter } 19861b36c03eSAdrian Hunter sym = dso__next_symbol(sym); 19871b36c03eSAdrian Hunter } 19881b36c03eSAdrian Hunter 19891b36c03eSAdrian Hunter if (!*start) 19901b36c03eSAdrian Hunter return sym_not_found_error(sym_name, idx); 19911b36c03eSAdrian Hunter 19921b36c03eSAdrian Hunter return 0; 19931b36c03eSAdrian Hunter } 19941b36c03eSAdrian Hunter 19951b36c03eSAdrian Hunter static int addr_filter__entire_dso(struct addr_filter *filt, struct dso *dso) 19961b36c03eSAdrian Hunter { 199757176601SAdrian Hunter if (dso__data_file_size(dso, NULL)) { 199857176601SAdrian Hunter pr_err("Failed to determine filter for %s\nCannot determine file size.\n", 19991b36c03eSAdrian Hunter filt->filename); 20001b36c03eSAdrian Hunter return -EINVAL; 20011b36c03eSAdrian Hunter } 20021b36c03eSAdrian Hunter 200357176601SAdrian Hunter filt->addr = 0; 200457176601SAdrian Hunter filt->size = dso->data.file_size; 20051b36c03eSAdrian Hunter 20061b36c03eSAdrian Hunter return 0; 20071b36c03eSAdrian Hunter } 20081b36c03eSAdrian Hunter 20091b36c03eSAdrian Hunter static int addr_filter__resolve_syms(struct addr_filter *filt) 20101b36c03eSAdrian Hunter { 20111b36c03eSAdrian Hunter u64 start, size; 20121b36c03eSAdrian Hunter struct dso *dso; 20131b36c03eSAdrian Hunter int err = 0; 20141b36c03eSAdrian Hunter 20151b36c03eSAdrian Hunter if (!filt->sym_from && !filt->sym_to) 20161b36c03eSAdrian Hunter return 0; 20171b36c03eSAdrian Hunter 20181b36c03eSAdrian Hunter if (!filt->filename) 20191b36c03eSAdrian Hunter return addr_filter__resolve_kernel_syms(filt); 20201b36c03eSAdrian Hunter 20211b36c03eSAdrian Hunter dso = load_dso(filt->filename); 20221b36c03eSAdrian Hunter if (!dso) { 20231b36c03eSAdrian Hunter pr_err("Failed to load symbols from: %s\n", filt->filename); 20241b36c03eSAdrian Hunter return -EINVAL; 20251b36c03eSAdrian Hunter } 20261b36c03eSAdrian Hunter 20271b36c03eSAdrian Hunter if (filt->sym_from && !strcmp(filt->sym_from, "*")) { 20281b36c03eSAdrian Hunter err = addr_filter__entire_dso(filt, dso); 20291b36c03eSAdrian Hunter goto put_dso; 20301b36c03eSAdrian Hunter } 20311b36c03eSAdrian Hunter 20321b36c03eSAdrian Hunter if (filt->sym_from) { 20331b36c03eSAdrian Hunter err = find_dso_sym(dso, filt->sym_from, &start, &size, 20341b36c03eSAdrian Hunter filt->sym_from_idx); 20351b36c03eSAdrian Hunter if (err) 20361b36c03eSAdrian Hunter goto put_dso; 20371b36c03eSAdrian Hunter filt->addr = start; 20381b36c03eSAdrian Hunter if (filt->range && !filt->size && !filt->sym_to) 20391b36c03eSAdrian Hunter filt->size = size; 20401b36c03eSAdrian Hunter } 20411b36c03eSAdrian Hunter 20421b36c03eSAdrian Hunter if (filt->sym_to) { 20431b36c03eSAdrian Hunter err = find_dso_sym(dso, filt->sym_to, &start, &size, 20441b36c03eSAdrian Hunter filt->sym_to_idx); 20451b36c03eSAdrian Hunter if (err) 20461b36c03eSAdrian Hunter goto put_dso; 20471b36c03eSAdrian Hunter 20481b36c03eSAdrian Hunter err = check_end_after_start(filt, start, size); 20491b36c03eSAdrian Hunter if (err) 20501b36c03eSAdrian Hunter return err; 20511b36c03eSAdrian Hunter 20521b36c03eSAdrian Hunter filt->size = start + size - filt->addr; 20531b36c03eSAdrian Hunter } 20541b36c03eSAdrian Hunter 20551b36c03eSAdrian Hunter put_dso: 20561b36c03eSAdrian Hunter dso__put(dso); 20571b36c03eSAdrian Hunter 20581b36c03eSAdrian Hunter return err; 20591b36c03eSAdrian Hunter } 20601b36c03eSAdrian Hunter 20611b36c03eSAdrian Hunter static char *addr_filter__to_str(struct addr_filter *filt) 20621b36c03eSAdrian Hunter { 20631b36c03eSAdrian Hunter char filename_buf[PATH_MAX]; 20641b36c03eSAdrian Hunter const char *at = ""; 20651b36c03eSAdrian Hunter const char *fn = ""; 20661b36c03eSAdrian Hunter char *filter; 20671b36c03eSAdrian Hunter int err; 20681b36c03eSAdrian Hunter 20691b36c03eSAdrian Hunter if (filt->filename) { 20701b36c03eSAdrian Hunter at = "@"; 20711b36c03eSAdrian Hunter fn = realpath(filt->filename, filename_buf); 20721b36c03eSAdrian Hunter if (!fn) 20731b36c03eSAdrian Hunter return NULL; 20741b36c03eSAdrian Hunter } 20751b36c03eSAdrian Hunter 20761b36c03eSAdrian Hunter if (filt->range) { 20771b36c03eSAdrian Hunter err = asprintf(&filter, "%s 0x%"PRIx64"/0x%"PRIx64"%s%s", 20781b36c03eSAdrian Hunter filt->action, filt->addr, filt->size, at, fn); 20791b36c03eSAdrian Hunter } else { 20801b36c03eSAdrian Hunter err = asprintf(&filter, "%s 0x%"PRIx64"%s%s", 20811b36c03eSAdrian Hunter filt->action, filt->addr, at, fn); 20821b36c03eSAdrian Hunter } 20831b36c03eSAdrian Hunter 20841b36c03eSAdrian Hunter return err < 0 ? NULL : filter; 20851b36c03eSAdrian Hunter } 20861b36c03eSAdrian Hunter 20871b36c03eSAdrian Hunter static int parse_addr_filter(struct perf_evsel *evsel, const char *filter, 20881b36c03eSAdrian Hunter int max_nr) 20891b36c03eSAdrian Hunter { 20901b36c03eSAdrian Hunter struct addr_filters filts; 20911b36c03eSAdrian Hunter struct addr_filter *filt; 20921b36c03eSAdrian Hunter int err; 20931b36c03eSAdrian Hunter 20941b36c03eSAdrian Hunter addr_filters__init(&filts); 20951b36c03eSAdrian Hunter 20961b36c03eSAdrian Hunter err = addr_filters__parse_bare_filter(&filts, filter); 20971b36c03eSAdrian Hunter if (err) 20981b36c03eSAdrian Hunter goto out_exit; 20991b36c03eSAdrian Hunter 21001b36c03eSAdrian Hunter if (filts.cnt > max_nr) { 21011b36c03eSAdrian Hunter pr_err("Error: number of address filters (%d) exceeds maximum (%d)\n", 21021b36c03eSAdrian Hunter filts.cnt, max_nr); 21031b36c03eSAdrian Hunter err = -EINVAL; 21041b36c03eSAdrian Hunter goto out_exit; 21051b36c03eSAdrian Hunter } 21061b36c03eSAdrian Hunter 21071b36c03eSAdrian Hunter list_for_each_entry(filt, &filts.head, list) { 21081b36c03eSAdrian Hunter char *new_filter; 21091b36c03eSAdrian Hunter 21101b36c03eSAdrian Hunter err = addr_filter__resolve_syms(filt); 21111b36c03eSAdrian Hunter if (err) 21121b36c03eSAdrian Hunter goto out_exit; 21131b36c03eSAdrian Hunter 21141b36c03eSAdrian Hunter new_filter = addr_filter__to_str(filt); 21151b36c03eSAdrian Hunter if (!new_filter) { 21161b36c03eSAdrian Hunter err = -ENOMEM; 21171b36c03eSAdrian Hunter goto out_exit; 21181b36c03eSAdrian Hunter } 21191b36c03eSAdrian Hunter 21201b36c03eSAdrian Hunter if (perf_evsel__append_addr_filter(evsel, new_filter)) { 21211b36c03eSAdrian Hunter err = -ENOMEM; 21221b36c03eSAdrian Hunter goto out_exit; 21231b36c03eSAdrian Hunter } 21241b36c03eSAdrian Hunter } 21251b36c03eSAdrian Hunter 21261b36c03eSAdrian Hunter out_exit: 21271b36c03eSAdrian Hunter addr_filters__exit(&filts); 21281b36c03eSAdrian Hunter 21291b36c03eSAdrian Hunter if (err) { 21301b36c03eSAdrian Hunter pr_err("Failed to parse address filter: '%s'\n", filter); 21311b36c03eSAdrian Hunter pr_err("Filter format is: filter|start|stop|tracestop <start symbol or address> [/ <end symbol or size>] [@<file name>]\n"); 21321b36c03eSAdrian Hunter pr_err("Where multiple filters are separated by space or comma.\n"); 21331b36c03eSAdrian Hunter } 21341b36c03eSAdrian Hunter 21351b36c03eSAdrian Hunter return err; 21361b36c03eSAdrian Hunter } 21371b36c03eSAdrian Hunter 21381b36c03eSAdrian Hunter static struct perf_pmu *perf_evsel__find_pmu(struct perf_evsel *evsel) 21391b36c03eSAdrian Hunter { 21401b36c03eSAdrian Hunter struct perf_pmu *pmu = NULL; 21411b36c03eSAdrian Hunter 21421b36c03eSAdrian Hunter while ((pmu = perf_pmu__scan(pmu)) != NULL) { 21431b36c03eSAdrian Hunter if (pmu->type == evsel->attr.type) 21441b36c03eSAdrian Hunter break; 21451b36c03eSAdrian Hunter } 21461b36c03eSAdrian Hunter 21471b36c03eSAdrian Hunter return pmu; 21481b36c03eSAdrian Hunter } 21491b36c03eSAdrian Hunter 21501b36c03eSAdrian Hunter static int perf_evsel__nr_addr_filter(struct perf_evsel *evsel) 21511b36c03eSAdrian Hunter { 21521b36c03eSAdrian Hunter struct perf_pmu *pmu = perf_evsel__find_pmu(evsel); 21531b36c03eSAdrian Hunter int nr_addr_filters = 0; 21541b36c03eSAdrian Hunter 21551b36c03eSAdrian Hunter if (!pmu) 21561b36c03eSAdrian Hunter return 0; 21571b36c03eSAdrian Hunter 21581b36c03eSAdrian Hunter perf_pmu__scan_file(pmu, "nr_addr_filters", "%d", &nr_addr_filters); 21591b36c03eSAdrian Hunter 21601b36c03eSAdrian Hunter return nr_addr_filters; 21611b36c03eSAdrian Hunter } 21621b36c03eSAdrian Hunter 21631b36c03eSAdrian Hunter int auxtrace_parse_filters(struct perf_evlist *evlist) 21641b36c03eSAdrian Hunter { 21651b36c03eSAdrian Hunter struct perf_evsel *evsel; 21661b36c03eSAdrian Hunter char *filter; 21671b36c03eSAdrian Hunter int err, max_nr; 21681b36c03eSAdrian Hunter 21691b36c03eSAdrian Hunter evlist__for_each_entry(evlist, evsel) { 21701b36c03eSAdrian Hunter filter = evsel->filter; 21711b36c03eSAdrian Hunter max_nr = perf_evsel__nr_addr_filter(evsel); 21721b36c03eSAdrian Hunter if (!filter || !max_nr) 21731b36c03eSAdrian Hunter continue; 21741b36c03eSAdrian Hunter evsel->filter = NULL; 21751b36c03eSAdrian Hunter err = parse_addr_filter(evsel, filter, max_nr); 21761b36c03eSAdrian Hunter free(filter); 21771b36c03eSAdrian Hunter if (err) 21781b36c03eSAdrian Hunter return err; 21791b36c03eSAdrian Hunter pr_debug("Address filter: %s\n", evsel->filter); 21801b36c03eSAdrian Hunter } 21811b36c03eSAdrian Hunter 21821b36c03eSAdrian Hunter return 0; 21831b36c03eSAdrian Hunter } 2184