linux/tools/testing/selftests/bpf/trace_helpers.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <stdio.h>
   3#include <stdlib.h>
   4#include <string.h>
   5#include <assert.h>
   6#include <errno.h>
   7#include <poll.h>
   8#include <unistd.h>
   9#include <linux/perf_event.h>
  10#include <sys/mman.h>
  11#include "trace_helpers.h"
  12
  13#define MAX_SYMS 300000
  14static struct ksym syms[MAX_SYMS];
  15static int sym_cnt;
  16
  17static int ksym_cmp(const void *p1, const void *p2)
  18{
  19        return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
  20}
  21
  22int load_kallsyms(void)
  23{
  24        FILE *f = fopen("/proc/kallsyms", "r");
  25        char func[256], buf[256];
  26        char symbol;
  27        void *addr;
  28        int i = 0;
  29
  30        if (!f)
  31                return -ENOENT;
  32
  33        while (!feof(f)) {
  34                if (!fgets(buf, sizeof(buf), f))
  35                        break;
  36                if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
  37                        break;
  38                if (!addr)
  39                        continue;
  40                syms[i].addr = (long) addr;
  41                syms[i].name = strdup(func);
  42                i++;
  43        }
  44        sym_cnt = i;
  45        qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
  46        return 0;
  47}
  48
  49struct ksym *ksym_search(long key)
  50{
  51        int start = 0, end = sym_cnt;
  52        int result;
  53
  54        while (start < end) {
  55                size_t mid = start + (end - start) / 2;
  56
  57                result = key - syms[mid].addr;
  58                if (result < 0)
  59                        end = mid;
  60                else if (result > 0)
  61                        start = mid + 1;
  62                else
  63                        return &syms[mid];
  64        }
  65
  66        if (start >= 1 && syms[start - 1].addr < key &&
  67            key < syms[start].addr)
  68                /* valid ksym */
  69                return &syms[start - 1];
  70
  71        /* out of range. return _stext */
  72        return &syms[0];
  73}
  74
  75long ksym_get_addr(const char *name)
  76{
  77        int i;
  78
  79        for (i = 0; i < sym_cnt; i++) {
  80                if (strcmp(syms[i].name, name) == 0)
  81                        return syms[i].addr;
  82        }
  83
  84        return 0;
  85}
  86
  87static int page_size;
  88static int page_cnt = 8;
  89static struct perf_event_mmap_page *header;
  90
  91int perf_event_mmap_header(int fd, struct perf_event_mmap_page **header)
  92{
  93        void *base;
  94        int mmap_size;
  95
  96        page_size = getpagesize();
  97        mmap_size = page_size * (page_cnt + 1);
  98
  99        base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
 100        if (base == MAP_FAILED) {
 101                printf("mmap err\n");
 102                return -1;
 103        }
 104
 105        *header = base;
 106        return 0;
 107}
 108
 109int perf_event_mmap(int fd)
 110{
 111        return perf_event_mmap_header(fd, &header);
 112}
 113
 114static int perf_event_poll(int fd)
 115{
 116        struct pollfd pfd = { .fd = fd, .events = POLLIN };
 117
 118        return poll(&pfd, 1, 1000);
 119}
 120
 121struct perf_event_sample {
 122        struct perf_event_header header;
 123        __u32 size;
 124        char data[];
 125};
 126
 127static enum bpf_perf_event_ret bpf_perf_event_print(void *event, void *priv)
 128{
 129        struct perf_event_sample *e = event;
 130        perf_event_print_fn fn = priv;
 131        int ret;
 132
 133        if (e->header.type == PERF_RECORD_SAMPLE) {
 134                ret = fn(e->data, e->size);
 135                if (ret != LIBBPF_PERF_EVENT_CONT)
 136                        return ret;
 137        } else if (e->header.type == PERF_RECORD_LOST) {
 138                struct {
 139                        struct perf_event_header header;
 140                        __u64 id;
 141                        __u64 lost;
 142                } *lost = (void *) e;
 143                printf("lost %lld events\n", lost->lost);
 144        } else {
 145                printf("unknown event type=%d size=%d\n",
 146                       e->header.type, e->header.size);
 147        }
 148
 149        return LIBBPF_PERF_EVENT_CONT;
 150}
 151
 152int perf_event_poller(int fd, perf_event_print_fn output_fn)
 153{
 154        enum bpf_perf_event_ret ret;
 155        void *buf = NULL;
 156        size_t len = 0;
 157
 158        for (;;) {
 159                perf_event_poll(fd);
 160                ret = bpf_perf_event_read_simple(header, page_cnt * page_size,
 161                                                 page_size, &buf, &len,
 162                                                 bpf_perf_event_print,
 163                                                 output_fn);
 164                if (ret != LIBBPF_PERF_EVENT_CONT)
 165                        break;
 166        }
 167        free(buf);
 168
 169        return ret;
 170}
 171
 172int perf_event_poller_multi(int *fds, struct perf_event_mmap_page **headers,
 173                            int num_fds, perf_event_print_fn output_fn)
 174{
 175        enum bpf_perf_event_ret ret;
 176        struct pollfd *pfds;
 177        void *buf = NULL;
 178        size_t len = 0;
 179        int i;
 180
 181        pfds = calloc(num_fds, sizeof(*pfds));
 182        if (!pfds)
 183                return LIBBPF_PERF_EVENT_ERROR;
 184
 185        for (i = 0; i < num_fds; i++) {
 186                pfds[i].fd = fds[i];
 187                pfds[i].events = POLLIN;
 188        }
 189
 190        for (;;) {
 191                poll(pfds, num_fds, 1000);
 192                for (i = 0; i < num_fds; i++) {
 193                        if (!pfds[i].revents)
 194                                continue;
 195
 196                        ret = bpf_perf_event_read_simple(headers[i],
 197                                                         page_cnt * page_size,
 198                                                         page_size, &buf, &len,
 199                                                         bpf_perf_event_print,
 200                                                         output_fn);
 201                        if (ret != LIBBPF_PERF_EVENT_CONT)
 202                                break;
 203                }
 204        }
 205        free(buf);
 206        free(pfds);
 207
 208        return ret;
 209}
 210