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