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 <fcntl.h>
   8#include <poll.h>
   9#include <unistd.h>
  10#include <linux/perf_event.h>
  11#include <sys/mman.h>
  12#include "trace_helpers.h"
  13
  14#define DEBUGFS "/sys/kernel/debug/tracing/"
  15
  16#define MAX_SYMS 300000
  17static struct ksym syms[MAX_SYMS];
  18static int sym_cnt;
  19
  20static int ksym_cmp(const void *p1, const void *p2)
  21{
  22        return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
  23}
  24
  25int load_kallsyms(void)
  26{
  27        FILE *f = fopen("/proc/kallsyms", "r");
  28        char func[256], buf[256];
  29        char symbol;
  30        void *addr;
  31        int i = 0;
  32
  33        if (!f)
  34                return -ENOENT;
  35
  36        while (fgets(buf, sizeof(buf), f)) {
  37                if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
  38                        break;
  39                if (!addr)
  40                        continue;
  41                syms[i].addr = (long) addr;
  42                syms[i].name = strdup(func);
  43                i++;
  44        }
  45        fclose(f);
  46        sym_cnt = i;
  47        qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
  48        return 0;
  49}
  50
  51struct ksym *ksym_search(long key)
  52{
  53        int start = 0, end = sym_cnt;
  54        int result;
  55
  56        /* kallsyms not loaded. return NULL */
  57        if (sym_cnt <= 0)
  58                return NULL;
  59
  60        while (start < end) {
  61                size_t mid = start + (end - start) / 2;
  62
  63                result = key - syms[mid].addr;
  64                if (result < 0)
  65                        end = mid;
  66                else if (result > 0)
  67                        start = mid + 1;
  68                else
  69                        return &syms[mid];
  70        }
  71
  72        if (start >= 1 && syms[start - 1].addr < key &&
  73            key < syms[start].addr)
  74                /* valid ksym */
  75                return &syms[start - 1];
  76
  77        /* out of range. return _stext */
  78        return &syms[0];
  79}
  80
  81long ksym_get_addr(const char *name)
  82{
  83        int i;
  84
  85        for (i = 0; i < sym_cnt; i++) {
  86                if (strcmp(syms[i].name, name) == 0)
  87                        return syms[i].addr;
  88        }
  89
  90        return 0;
  91}
  92
  93/* open kallsyms and read symbol addresses on the fly. Without caching all symbols,
  94 * this is faster than load + find.
  95 */
  96int kallsyms_find(const char *sym, unsigned long long *addr)
  97{
  98        char type, name[500];
  99        unsigned long long value;
 100        int err = 0;
 101        FILE *f;
 102
 103        f = fopen("/proc/kallsyms", "r");
 104        if (!f)
 105                return -EINVAL;
 106
 107        while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
 108                if (strcmp(name, sym) == 0) {
 109                        *addr = value;
 110                        goto out;
 111                }
 112        }
 113        err = -ENOENT;
 114
 115out:
 116        fclose(f);
 117        return err;
 118}
 119
 120void read_trace_pipe(void)
 121{
 122        int trace_fd;
 123
 124        trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
 125        if (trace_fd < 0)
 126                return;
 127
 128        while (1) {
 129                static char buf[4096];
 130                ssize_t sz;
 131
 132                sz = read(trace_fd, buf, sizeof(buf) - 1);
 133                if (sz > 0) {
 134                        buf[sz] = 0;
 135                        puts(buf);
 136                }
 137        }
 138}
 139