1 // SPDX-License-Identifier: GPL-2.0
12 #include <linux/perf_event.h>
14 #include <sys/ioctl.h>
16 #include "trace_helpers.h"
17 #include <linux/limits.h>
20 #include "bpf/libbpf_internal.h"
22 #define TRACEFS_PIPE "/sys/kernel/tracing/trace_pipe"
23 #define DEBUGFS_PIPE "/sys/kernel/debug/tracing/trace_pipe"
31 static struct ksyms *ksyms;
32 static pthread_mutex_t ksyms_mutex = PTHREAD_MUTEX_INITIALIZER;
34 static int ksyms__add_symbol(struct ksyms *ksyms, const char *name,
42 ksyms->syms[ksyms->sym_cnt].addr = addr;
43 ksyms->syms[ksyms->sym_cnt].name = tmp;
48 void free_kallsyms_local(struct ksyms *ksyms)
60 for (i = 0; i < ksyms->sym_cnt; i++)
61 free(ksyms->syms[i].name);
66 static struct ksyms *load_kallsyms_local_common(ksym_cmp_t cmp_cb)
69 char func[256], buf[256];
75 f = fopen("/proc/kallsyms", "r");
79 ksyms = calloc(1, sizeof(struct ksyms));
85 while (fgets(buf, sizeof(buf), f)) {
86 if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
91 ret = libbpf_ensure_mem((void **) &ksyms->syms, &ksyms->sym_cap,
92 sizeof(struct ksym), ksyms->sym_cnt + 1);
95 ret = ksyms__add_symbol(ksyms, func, (unsigned long)addr);
100 qsort(ksyms->syms, ksyms->sym_cnt, sizeof(struct ksym), cmp_cb);
105 free_kallsyms_local(ksyms);
109 static int ksym_cmp(const void *p1, const void *p2)
111 return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
114 struct ksyms *load_kallsyms_local(void)
116 return load_kallsyms_local_common(ksym_cmp);
119 struct ksyms *load_kallsyms_custom_local(ksym_cmp_t cmp_cb)
121 return load_kallsyms_local_common(cmp_cb);
124 int load_kallsyms(void)
126 pthread_mutex_lock(&ksyms_mutex);
128 ksyms = load_kallsyms_local();
129 pthread_mutex_unlock(&ksyms_mutex);
130 return ksyms ? 0 : 1;
133 struct ksym *ksym_search_local(struct ksyms *ksyms, long key)
135 int start = 0, end = ksyms->sym_cnt;
138 /* kallsyms not loaded. return NULL */
139 if (ksyms->sym_cnt <= 0)
142 while (start < end) {
143 size_t mid = start + (end - start) / 2;
145 result = key - ksyms->syms[mid].addr;
151 return &ksyms->syms[mid];
154 if (start >= 1 && ksyms->syms[start - 1].addr < key &&
155 key < ksyms->syms[start].addr)
157 return &ksyms->syms[start - 1];
159 /* out of range. return _stext */
160 return &ksyms->syms[0];
163 struct ksym *search_kallsyms_custom_local(struct ksyms *ksyms, const void *p,
164 ksym_search_cmp_t cmp_cb)
166 int start = 0, mid, end = ksyms->sym_cnt;
170 while (start < end) {
171 mid = start + (end - start) / 2;
172 ks = &ksyms->syms[mid];
173 result = cmp_cb(p, ks);
185 struct ksym *ksym_search(long key)
189 return ksym_search_local(ksyms, key);
192 long ksym_get_addr_local(struct ksyms *ksyms, const char *name)
196 for (i = 0; i < ksyms->sym_cnt; i++) {
197 if (strcmp(ksyms->syms[i].name, name) == 0)
198 return ksyms->syms[i].addr;
204 long ksym_get_addr(const char *name)
208 return ksym_get_addr_local(ksyms, name);
211 /* open kallsyms and read symbol addresses on the fly. Without caching all symbols,
212 * this is faster than load + find.
214 int kallsyms_find(const char *sym, unsigned long long *addr)
216 char type, name[500], *match;
217 unsigned long long value;
221 f = fopen("/proc/kallsyms", "r");
225 while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
226 /* If CONFIG_LTO_CLANG_THIN is enabled, static variable/function
227 * symbols could be promoted to global due to cross-file inlining.
228 * For such cases, clang compiler will add .llvm.<hash> suffix
229 * to those symbols to avoid potential naming conflict.
230 * Let us ignore .llvm.<hash> suffix during symbol comparison.
233 match = strstr(name, ".llvm.");
237 if (strcmp(name, sym) == 0) {
250 int env_verbosity __weak = 0;
252 static int procmap_query(int fd, const void *addr, __u32 query_flags, size_t *start, size_t *offset, int *flags)
254 char path_buf[PATH_MAX], build_id_buf[20];
255 struct procmap_query q;
258 memset(&q, 0, sizeof(q));
260 q.query_flags = query_flags;
261 q.query_addr = (__u64)addr;
262 q.vma_name_addr = (__u64)path_buf;
263 q.vma_name_size = sizeof(path_buf);
264 q.build_id_addr = (__u64)build_id_buf;
265 q.build_id_size = sizeof(build_id_buf);
267 err = ioctl(fd, PROCMAP_QUERY, &q);
271 return -EOPNOTSUPP; /* ioctl() not implemented yet */
273 return -ESRCH; /* vma not found */
277 if (env_verbosity >= 1) {
278 printf("VMA FOUND (addr %08lx): %08lx-%08lx %c%c%c%c %08lx %02x:%02x %ld %s (build ID: %s, %d bytes)\n",
279 (long)addr, (long)q.vma_start, (long)q.vma_end,
280 (q.vma_flags & PROCMAP_QUERY_VMA_READABLE) ? 'r' : '-',
281 (q.vma_flags & PROCMAP_QUERY_VMA_WRITABLE) ? 'w' : '-',
282 (q.vma_flags & PROCMAP_QUERY_VMA_EXECUTABLE) ? 'x' : '-',
283 (q.vma_flags & PROCMAP_QUERY_VMA_SHARED) ? 's' : 'p',
284 (long)q.vma_offset, q.dev_major, q.dev_minor, (long)q.inode,
285 q.vma_name_size ? path_buf : "",
286 q.build_id_size ? "YES" : "NO",
290 *start = q.vma_start;
291 *offset = q.vma_offset;
292 *flags = q.vma_flags;
296 # ifndef PROCMAP_QUERY_VMA_EXECUTABLE
297 # define PROCMAP_QUERY_VMA_EXECUTABLE 0x04
300 static int procmap_query(int fd, const void *addr, __u32 query_flags, size_t *start, size_t *offset, int *flags)
306 ssize_t get_uprobe_offset(const void *addr)
308 size_t start, base, end;
313 f = fopen("/proc/self/maps", "r");
317 /* requested executable VMA only */
318 err = procmap_query(fileno(f), addr, PROCMAP_QUERY_VMA_EXECUTABLE, &start, &base, &flags);
319 if (err == -EOPNOTSUPP) {
322 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
323 if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
338 #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
340 #define OP_RT_RA_MASK 0xffff0000UL
341 #define LIS_R2 0x3c400000UL
342 #define ADDIS_R2_R12 0x3c4c0000UL
343 #define ADDI_R2_R2 0x38420000UL
346 * A PPC64 ABIv2 function may have a local and a global entry
347 * point. We need to use the local entry point when patching
348 * functions, so identify and step over the global entry point
351 * The global entry point sequence is always of the form:
356 * A linker optimisation may convert the addis to lis:
362 const __u32 *insn = (const __u32 *)(uintptr_t)addr;
364 if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
365 ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
366 ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
367 return (uintptr_t)(insn + 2) - start + base;
370 return (uintptr_t)addr - start + base;
373 ssize_t get_rel_offset(uintptr_t addr)
375 size_t start, end, offset;
380 f = fopen("/proc/self/maps", "r");
384 err = procmap_query(fileno(f), (const void *)addr, 0, &start, &offset, &flags);
387 return (size_t)addr - start + offset;
388 } else if (err != -EOPNOTSUPP) {
392 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
393 if (addr >= start && addr < end) {
395 return (size_t)addr - start + offset;
405 parse_build_id_buf(const void *note_start, Elf32_Word note_size, char *build_id)
407 Elf32_Word note_offs = 0;
409 while (note_offs + sizeof(Elf32_Nhdr) < note_size) {
410 Elf32_Nhdr *nhdr = (Elf32_Nhdr *)(note_start + note_offs);
412 if (nhdr->n_type == 3 && nhdr->n_namesz == sizeof("GNU") &&
413 !strcmp((char *)(nhdr + 1), "GNU") && nhdr->n_descsz > 0 &&
414 nhdr->n_descsz <= BPF_BUILD_ID_SIZE) {
415 memcpy(build_id, note_start + note_offs +
416 ALIGN(sizeof("GNU"), 4) + sizeof(Elf32_Nhdr), nhdr->n_descsz);
417 memset(build_id + nhdr->n_descsz, 0, BPF_BUILD_ID_SIZE - nhdr->n_descsz);
418 return (int) nhdr->n_descsz;
421 note_offs = note_offs + sizeof(Elf32_Nhdr) +
422 ALIGN(nhdr->n_namesz, 4) + ALIGN(nhdr->n_descsz, 4);
428 /* Reads binary from *path* file and returns it in the *build_id* buffer
429 * with *size* which is expected to be at least BPF_BUILD_ID_SIZE bytes.
430 * Returns size of build id on success. On error the error value is
433 int read_build_id(const char *path, char *build_id, size_t size)
435 int fd, err = -EINVAL;
440 if (size < BPF_BUILD_ID_SIZE)
443 fd = open(path, O_RDONLY | O_CLOEXEC);
447 (void)elf_version(EV_CURRENT);
449 elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
452 if (elf_kind(elf) != ELF_K_ELF)
454 if (!gelf_getehdr(elf, &ehdr))
457 for (i = 0; i < ehdr.e_phnum; i++) {
458 GElf_Phdr mem, *phdr;
461 phdr = gelf_getphdr(elf, i, &mem);
464 if (phdr->p_type != PT_NOTE)
466 data = elf_rawfile(elf, &max);
469 if (phdr->p_offset + phdr->p_memsz > max)
471 err = parse_build_id_buf(data + phdr->p_offset, phdr->p_memsz, build_id);
483 int read_trace_pipe_iter(void (*cb)(const char *str, void *data), void *data, int iter)
489 if (access(TRACEFS_PIPE, F_OK) == 0)
490 fp = fopen(TRACEFS_PIPE, "r");
492 fp = fopen(DEBUGFS_PIPE, "r");
496 /* We do not want to wait forever when iter is specified. */
498 fcntl(fileno(fp), F_SETFL, O_NONBLOCK);
500 while ((n = getline(&buf, &buflen, fp) >= 0) || errno == EAGAIN) {
503 if (iter && !(--iter))
513 static void trace_pipe_cb(const char *str, void *data)
518 void read_trace_pipe(void)
520 read_trace_pipe_iter(trace_pipe_cb, NULL, 0);