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 #include <linux/limits.h> 15 #include <libelf.h> 16 #include <gelf.h> 17 18 #define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe" 19 #define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe" 20 21 #define MAX_SYMS 400000 22 static struct ksym syms[MAX_SYMS]; 23 static int sym_cnt; 24 25 static int ksym_cmp(const void *p1, const void *p2) 26 { 27 return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr; 28 } 29 30 int load_kallsyms_refresh(void) 31 { 32 FILE *f; 33 char func[256], buf[256]; 34 char symbol; 35 void *addr; 36 int i = 0; 37 38 sym_cnt = 0; 39 40 f = fopen("/proc/kallsyms", "r"); 41 if (!f) 42 return -ENOENT; 43 44 while (fgets(buf, sizeof(buf), f)) { 45 if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3) 46 break; 47 if (!addr) 48 continue; 49 if (i >= MAX_SYMS) 50 return -EFBIG; 51 52 syms[i].addr = (long) addr; 53 syms[i].name = strdup(func); 54 i++; 55 } 56 fclose(f); 57 sym_cnt = i; 58 qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp); 59 return 0; 60 } 61 62 int load_kallsyms(void) 63 { 64 /* 65 * This is called/used from multiplace places, 66 * load symbols just once. 67 */ 68 if (sym_cnt) 69 return 0; 70 return load_kallsyms_refresh(); 71 } 72 73 struct ksym *ksym_search(long key) 74 { 75 int start = 0, end = sym_cnt; 76 int result; 77 78 /* kallsyms not loaded. return NULL */ 79 if (sym_cnt <= 0) 80 return NULL; 81 82 while (start < end) { 83 size_t mid = start + (end - start) / 2; 84 85 result = key - syms[mid].addr; 86 if (result < 0) 87 end = mid; 88 else if (result > 0) 89 start = mid + 1; 90 else 91 return &syms[mid]; 92 } 93 94 if (start >= 1 && syms[start - 1].addr < key && 95 key < syms[start].addr) 96 /* valid ksym */ 97 return &syms[start - 1]; 98 99 /* out of range. return _stext */ 100 return &syms[0]; 101 } 102 103 long ksym_get_addr(const char *name) 104 { 105 int i; 106 107 for (i = 0; i < sym_cnt; i++) { 108 if (strcmp(syms[i].name, name) == 0) 109 return syms[i].addr; 110 } 111 112 return 0; 113 } 114 115 /* open kallsyms and read symbol addresses on the fly. Without caching all symbols, 116 * this is faster than load + find. 117 */ 118 int kallsyms_find(const char *sym, unsigned long long *addr) 119 { 120 char type, name[500]; 121 unsigned long long value; 122 int err = 0; 123 FILE *f; 124 125 f = fopen("/proc/kallsyms", "r"); 126 if (!f) 127 return -EINVAL; 128 129 while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) { 130 if (strcmp(name, sym) == 0) { 131 *addr = value; 132 goto out; 133 } 134 } 135 err = -ENOENT; 136 137 out: 138 fclose(f); 139 return err; 140 } 141 142 void read_trace_pipe(void) 143 { 144 int trace_fd; 145 146 if (access(TRACEFS_PIPE, F_OK) == 0) 147 trace_fd = open(TRACEFS_PIPE, O_RDONLY, 0); 148 else 149 trace_fd = open(DEBUGFS_PIPE, O_RDONLY, 0); 150 if (trace_fd < 0) 151 return; 152 153 while (1) { 154 static char buf[4096]; 155 ssize_t sz; 156 157 sz = read(trace_fd, buf, sizeof(buf) - 1); 158 if (sz > 0) { 159 buf[sz] = 0; 160 puts(buf); 161 } 162 } 163 } 164 165 ssize_t get_uprobe_offset(const void *addr) 166 { 167 size_t start, end, base; 168 char buf[256]; 169 bool found = false; 170 FILE *f; 171 172 f = fopen("/proc/self/maps", "r"); 173 if (!f) 174 return -errno; 175 176 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) { 177 if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) { 178 found = true; 179 break; 180 } 181 } 182 183 fclose(f); 184 185 if (!found) 186 return -ESRCH; 187 188 #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2 189 190 #define OP_RT_RA_MASK 0xffff0000UL 191 #define LIS_R2 0x3c400000UL 192 #define ADDIS_R2_R12 0x3c4c0000UL 193 #define ADDI_R2_R2 0x38420000UL 194 195 /* 196 * A PPC64 ABIv2 function may have a local and a global entry 197 * point. We need to use the local entry point when patching 198 * functions, so identify and step over the global entry point 199 * sequence. 200 * 201 * The global entry point sequence is always of the form: 202 * 203 * addis r2,r12,XXXX 204 * addi r2,r2,XXXX 205 * 206 * A linker optimisation may convert the addis to lis: 207 * 208 * lis r2,XXXX 209 * addi r2,r2,XXXX 210 */ 211 { 212 const u32 *insn = (const u32 *)(uintptr_t)addr; 213 214 if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) || 215 ((*insn & OP_RT_RA_MASK) == LIS_R2)) && 216 ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2)) 217 return (uintptr_t)(insn + 2) - start + base; 218 } 219 #endif 220 return (uintptr_t)addr - start + base; 221 } 222 223 ssize_t get_rel_offset(uintptr_t addr) 224 { 225 size_t start, end, offset; 226 char buf[256]; 227 FILE *f; 228 229 f = fopen("/proc/self/maps", "r"); 230 if (!f) 231 return -errno; 232 233 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) { 234 if (addr >= start && addr < end) { 235 fclose(f); 236 return (size_t)addr - start + offset; 237 } 238 } 239 240 fclose(f); 241 return -EINVAL; 242 } 243 244 static int 245 parse_build_id_buf(const void *note_start, Elf32_Word note_size, char *build_id) 246 { 247 Elf32_Word note_offs = 0; 248 249 while (note_offs + sizeof(Elf32_Nhdr) < note_size) { 250 Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs); 251 252 if (nhdr->n_type == 3 && nhdr->n_namesz == sizeof("GNU") && 253 !strcmp((char *)(nhdr + 1), "GNU") && nhdr->n_descsz > 0 && 254 nhdr->n_descsz <= BPF_BUILD_ID_SIZE) { 255 memcpy(build_id, note_start + note_offs + 256 ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), nhdr->n_descsz); 257 memset(build_id + nhdr->n_descsz, 0, BPF_BUILD_ID_SIZE - nhdr->n_descsz); 258 return (int) nhdr->n_descsz; 259 } 260 261 note_offs = note_offs + sizeof(Elf32_Nhdr) + 262 ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4); 263 } 264 265 return -ENOENT; 266 } 267 268 /* Reads binary from *path* file and returns it in the *build_id* buffer 269 * with *size* which is expected to be at least BPF_BUILD_ID_SIZE bytes. 270 * Returns size of build id on success. On error the error value is 271 * returned. 272 */ 273 int read_build_id(const char *path, char *build_id, size_t size) 274 { 275 int fd, err = -EINVAL; 276 Elf *elf = NULL; 277 GElf_Ehdr ehdr; 278 size_t max, i; 279 280 if (size < BPF_BUILD_ID_SIZE) 281 return -EINVAL; 282 283 fd = open(path, O_RDONLY | O_CLOEXEC); 284 if (fd < 0) 285 return -errno; 286 287 (void)elf_version(EV_CURRENT); 288 289 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL); 290 if (!elf) 291 goto out; 292 if (elf_kind(elf) != ELF_K_ELF) 293 goto out; 294 if (!gelf_getehdr(elf, &ehdr)) 295 goto out; 296 297 for (i = 0; i < ehdr.e_phnum; i++) { 298 GElf_Phdr mem, *phdr; 299 char *data; 300 301 phdr = gelf_getphdr(elf, i, &mem); 302 if (!phdr) 303 goto out; 304 if (phdr->p_type != PT_NOTE) 305 continue; 306 data = elf_rawfile(elf, &max); 307 if (!data) 308 goto out; 309 if (phdr->p_offset + phdr->p_memsz > max) 310 goto out; 311 err = parse_build_id_buf(data + phdr->p_offset, phdr->p_memsz, build_id); 312 if (err > 0) 313 break; 314 } 315 316 out: 317 if (elf) 318 elf_end(elf); 319 close(fd); 320 return err; 321 } 322