0001
0002 #include <ctype.h>
0003 #include <stdio.h>
0004 #include <stdlib.h>
0005 #include <string.h>
0006 #include <assert.h>
0007 #include <errno.h>
0008 #include <fcntl.h>
0009 #include <poll.h>
0010 #include <unistd.h>
0011 #include <linux/perf_event.h>
0012 #include <sys/mman.h>
0013 #include "trace_helpers.h"
0014
0015 #define DEBUGFS "/sys/kernel/debug/tracing/"
0016
0017 #define MAX_SYMS 300000
0018 static struct ksym syms[MAX_SYMS];
0019 static int sym_cnt;
0020
0021 static int ksym_cmp(const void *p1, const void *p2)
0022 {
0023 return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
0024 }
0025
0026 int load_kallsyms(void)
0027 {
0028 FILE *f;
0029 char func[256], buf[256];
0030 char symbol;
0031 void *addr;
0032 int i = 0;
0033
0034
0035
0036
0037
0038 if (sym_cnt)
0039 return 0;
0040
0041 f = fopen("/proc/kallsyms", "r");
0042 if (!f)
0043 return -ENOENT;
0044
0045 while (fgets(buf, sizeof(buf), f)) {
0046 if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
0047 break;
0048 if (!addr)
0049 continue;
0050 syms[i].addr = (long) addr;
0051 syms[i].name = strdup(func);
0052 i++;
0053 }
0054 fclose(f);
0055 sym_cnt = i;
0056 qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
0057 return 0;
0058 }
0059
0060 struct ksym *ksym_search(long key)
0061 {
0062 int start = 0, end = sym_cnt;
0063 int result;
0064
0065
0066 if (sym_cnt <= 0)
0067 return NULL;
0068
0069 while (start < end) {
0070 size_t mid = start + (end - start) / 2;
0071
0072 result = key - syms[mid].addr;
0073 if (result < 0)
0074 end = mid;
0075 else if (result > 0)
0076 start = mid + 1;
0077 else
0078 return &syms[mid];
0079 }
0080
0081 if (start >= 1 && syms[start - 1].addr < key &&
0082 key < syms[start].addr)
0083
0084 return &syms[start - 1];
0085
0086
0087 return &syms[0];
0088 }
0089
0090 long ksym_get_addr(const char *name)
0091 {
0092 int i;
0093
0094 for (i = 0; i < sym_cnt; i++) {
0095 if (strcmp(syms[i].name, name) == 0)
0096 return syms[i].addr;
0097 }
0098
0099 return 0;
0100 }
0101
0102
0103
0104
0105 int kallsyms_find(const char *sym, unsigned long long *addr)
0106 {
0107 char type, name[500];
0108 unsigned long long value;
0109 int err = 0;
0110 FILE *f;
0111
0112 f = fopen("/proc/kallsyms", "r");
0113 if (!f)
0114 return -EINVAL;
0115
0116 while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
0117 if (strcmp(name, sym) == 0) {
0118 *addr = value;
0119 goto out;
0120 }
0121 }
0122 err = -ENOENT;
0123
0124 out:
0125 fclose(f);
0126 return err;
0127 }
0128
0129 void read_trace_pipe(void)
0130 {
0131 int trace_fd;
0132
0133 trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
0134 if (trace_fd < 0)
0135 return;
0136
0137 while (1) {
0138 static char buf[4096];
0139 ssize_t sz;
0140
0141 sz = read(trace_fd, buf, sizeof(buf) - 1);
0142 if (sz > 0) {
0143 buf[sz] = 0;
0144 puts(buf);
0145 }
0146 }
0147 }
0148
0149 ssize_t get_uprobe_offset(const void *addr)
0150 {
0151 size_t start, end, base;
0152 char buf[256];
0153 bool found = false;
0154 FILE *f;
0155
0156 f = fopen("/proc/self/maps", "r");
0157 if (!f)
0158 return -errno;
0159
0160 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {
0161 if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {
0162 found = true;
0163 break;
0164 }
0165 }
0166
0167 fclose(f);
0168
0169 if (!found)
0170 return -ESRCH;
0171
0172 #if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
0173
0174 #define OP_RT_RA_MASK 0xffff0000UL
0175 #define LIS_R2 0x3c400000UL
0176 #define ADDIS_R2_R12 0x3c4c0000UL
0177 #define ADDI_R2_R2 0x38420000UL
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195 {
0196 const u32 *insn = (const u32 *)(uintptr_t)addr;
0197
0198 if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
0199 ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
0200 ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
0201 return (uintptr_t)(insn + 2) - start + base;
0202 }
0203 #endif
0204 return (uintptr_t)addr - start + base;
0205 }
0206
0207 ssize_t get_rel_offset(uintptr_t addr)
0208 {
0209 size_t start, end, offset;
0210 char buf[256];
0211 FILE *f;
0212
0213 f = fopen("/proc/self/maps", "r");
0214 if (!f)
0215 return -errno;
0216
0217 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
0218 if (addr >= start && addr < end) {
0219 fclose(f);
0220 return (size_t)addr - start + offset;
0221 }
0222 }
0223
0224 fclose(f);
0225 return -EINVAL;
0226 }