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