linux/tools/testing/selftests/bpf/trace_helpers.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <ctype.h>
   3#include <stdio.h>
   4#include <stdlib.h>
   5#include <string.h>
   6#include <assert.h>
   7#include <errno.h>
   8#include <fcntl.h>
   9#include <poll.h>
  10#include <unistd.h>
  11#include <linux/perf_event.h>
  12#include <sys/mman.h>
  13#include "trace_helpers.h"
  14
  15#define DEBUGFS "/sys/kernel/debug/tracing/"
  16
  17#define MAX_SYMS 300000
  18static struct ksym syms[MAX_SYMS];
  19static int sym_cnt;
  20
  21static int ksym_cmp(const void *p1, const void *p2)
  22{
  23        return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
  24}
  25
  26int load_kallsyms(void)
  27{
  28        FILE *f = fopen("/proc/kallsyms", "r");
  29        char func[256], buf[256];
  30        char symbol;
  31        void *addr;
  32        int i = 0;
  33
  34        if (!f)
  35                return -ENOENT;
  36
  37        while (fgets(buf, sizeof(buf), f)) {
  38                if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
  39                        break;
  40                if (!addr)
  41                        continue;
  42                syms[i].addr = (long) addr;
  43                syms[i].name = strdup(func);
  44                i++;
  45        }
  46        fclose(f);
  47        sym_cnt = i;
  48        qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
  49        return 0;
  50}
  51
  52struct ksym *ksym_search(long key)
  53{
  54        int start = 0, end = sym_cnt;
  55        int result;
  56
  57        /* kallsyms not loaded. return NULL */
  58        if (sym_cnt <= 0)
  59                return NULL;
  60
  61        while (start < end) {
  62                size_t mid = start + (end - start) / 2;
  63
  64                result = key - syms[mid].addr;
  65                if (result < 0)
  66                        end = mid;
  67                else if (result > 0)
  68                        start = mid + 1;
  69                else
  70                        return &syms[mid];
  71        }
  72
  73        if (start >= 1 && syms[start - 1].addr < key &&
  74            key < syms[start].addr)
  75                /* valid ksym */
  76                return &syms[start - 1];
  77
  78        /* out of range. return _stext */
  79        return &syms[0];
  80}
  81
  82long ksym_get_addr(const char *name)
  83{
  84        int i;
  85
  86        for (i = 0; i < sym_cnt; i++) {
  87                if (strcmp(syms[i].name, name) == 0)
  88                        return syms[i].addr;
  89        }
  90
  91        return 0;
  92}
  93
  94/* open kallsyms and read symbol addresses on the fly. Without caching all symbols,
  95 * this is faster than load + find.
  96 */
  97int kallsyms_find(const char *sym, unsigned long long *addr)
  98{
  99        char type, name[500];
 100        unsigned long long value;
 101        int err = 0;
 102        FILE *f;
 103
 104        f = fopen("/proc/kallsyms", "r");
 105        if (!f)
 106                return -EINVAL;
 107
 108        while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
 109                if (strcmp(name, sym) == 0) {
 110                        *addr = value;
 111                        goto out;
 112                }
 113        }
 114        err = -ENOENT;
 115
 116out:
 117        fclose(f);
 118        return err;
 119}
 120
 121void read_trace_pipe(void)
 122{
 123        int trace_fd;
 124
 125        trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
 126        if (trace_fd < 0)
 127                return;
 128
 129        while (1) {
 130                static char buf[4096];
 131                ssize_t sz;
 132
 133                sz = read(trace_fd, buf, sizeof(buf) - 1);
 134                if (sz > 0) {
 135                        buf[sz] = 0;
 136                        puts(buf);
 137                }
 138        }
 139}
 140
 141#if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
 142
 143#define OP_RT_RA_MASK   0xffff0000UL
 144#define LIS_R2          0x3c400000UL
 145#define ADDIS_R2_R12    0x3c4c0000UL
 146#define ADDI_R2_R2      0x38420000UL
 147
 148ssize_t get_uprobe_offset(const void *addr, ssize_t base)
 149{
 150        u32 *insn = (u32 *)(uintptr_t)addr;
 151
 152        /*
 153         * A PPC64 ABIv2 function may have a local and a global entry
 154         * point. We need to use the local entry point when patching
 155         * functions, so identify and step over the global entry point
 156         * sequence.
 157         *
 158         * The global entry point sequence is always of the form:
 159         *
 160         * addis r2,r12,XXXX
 161         * addi  r2,r2,XXXX
 162         *
 163         * A linker optimisation may convert the addis to lis:
 164         *
 165         * lis   r2,XXXX
 166         * addi  r2,r2,XXXX
 167         */
 168        if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
 169             ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
 170            ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
 171                return (ssize_t)(insn + 2) - base;
 172        else
 173                return (uintptr_t)addr - base;
 174}
 175
 176#else
 177
 178ssize_t get_uprobe_offset(const void *addr, ssize_t base)
 179{
 180        return (uintptr_t)addr - base;
 181}
 182
 183#endif
 184
 185ssize_t get_base_addr(void)
 186{
 187        size_t start, offset;
 188        char buf[256];
 189        FILE *f;
 190
 191        f = fopen("/proc/self/maps", "r");
 192        if (!f)
 193                return -errno;
 194
 195        while (fscanf(f, "%zx-%*x %s %zx %*[^\n]\n",
 196                      &start, buf, &offset) == 3) {
 197                if (strcmp(buf, "r-xp") == 0) {
 198                        fclose(f);
 199                        return start - offset;
 200                }
 201        }
 202
 203        fclose(f);
 204        return -EINVAL;
 205}
 206
 207ssize_t get_rel_offset(uintptr_t addr)
 208{
 209        size_t start, end, offset;
 210        char buf[256];
 211        FILE *f;
 212
 213        f = fopen("/proc/self/maps", "r");
 214        if (!f)
 215                return -errno;
 216
 217        while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
 218                if (addr >= start && addr < end) {
 219                        fclose(f);
 220                        return (size_t)addr - start + offset;
 221                }
 222        }
 223
 224        fclose(f);
 225        return -EINVAL;
 226}
 227