1
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
15#define DEBUGFS "/sys/kernel/debug/tracing/"
16
17#define MAX_SYMS 300000
18static struct ksym syms[MAX_SYMS];
19static int sym_cnt;
20
21static int ksym_cmp(const void *p1, const void *p2)
22{
23 return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
24}
25
26int load_kallsyms(void)
27{
28 FILE *f = fopen("/proc/kallsyms", "r");
29 char func[256], buf[256];
30 char symbol;
31 void *addr;
32 int i = 0;
33
34 if (!f)
35 return -ENOENT;
36
37 while (fgets(buf, sizeof(buf), f)) {
38 if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
39 break;
40 if (!addr)
41 continue;
42 syms[i].addr = (long) addr;
43 syms[i].name = strdup(func);
44 i++;
45 }
46 fclose(f);
47 sym_cnt = i;
48 qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
49 return 0;
50}
51
52struct ksym *ksym_search(long key)
53{
54 int start = 0, end = sym_cnt;
55 int result;
56
57
58 if (sym_cnt <= 0)
59 return NULL;
60
61 while (start < end) {
62 size_t mid = start + (end - start) / 2;
63
64 result = key - syms[mid].addr;
65 if (result < 0)
66 end = mid;
67 else if (result > 0)
68 start = mid + 1;
69 else
70 return &syms[mid];
71 }
72
73 if (start >= 1 && syms[start - 1].addr < key &&
74 key < syms[start].addr)
75
76 return &syms[start - 1];
77
78
79 return &syms[0];
80}
81
82long ksym_get_addr(const char *name)
83{
84 int i;
85
86 for (i = 0; i < sym_cnt; i++) {
87 if (strcmp(syms[i].name, name) == 0)
88 return syms[i].addr;
89 }
90
91 return 0;
92}
93
94
95
96
97int kallsyms_find(const char *sym, unsigned long long *addr)
98{
99 char type, name[500];
100 unsigned long long value;
101 int err = 0;
102 FILE *f;
103
104 f = fopen("/proc/kallsyms", "r");
105 if (!f)
106 return -EINVAL;
107
108 while (fscanf(f, "%llx %c %499s%*[^\n]\n", &value, &type, name) > 0) {
109 if (strcmp(name, sym) == 0) {
110 *addr = value;
111 goto out;
112 }
113 }
114 err = -ENOENT;
115
116out:
117 fclose(f);
118 return err;
119}
120
121void read_trace_pipe(void)
122{
123 int trace_fd;
124
125 trace_fd = open(DEBUGFS "trace_pipe", O_RDONLY, 0);
126 if (trace_fd < 0)
127 return;
128
129 while (1) {
130 static char buf[4096];
131 ssize_t sz;
132
133 sz = read(trace_fd, buf, sizeof(buf) - 1);
134 if (sz > 0) {
135 buf[sz] = 0;
136 puts(buf);
137 }
138 }
139}
140
141#if defined(__powerpc64__) && defined(_CALL_ELF) && _CALL_ELF == 2
142
143#define OP_RT_RA_MASK 0xffff0000UL
144#define LIS_R2 0x3c400000UL
145#define ADDIS_R2_R12 0x3c4c0000UL
146#define ADDI_R2_R2 0x38420000UL
147
148ssize_t get_uprobe_offset(const void *addr, ssize_t base)
149{
150 u32 *insn = (u32 *)(uintptr_t)addr;
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168 if ((((*insn & OP_RT_RA_MASK) == ADDIS_R2_R12) ||
169 ((*insn & OP_RT_RA_MASK) == LIS_R2)) &&
170 ((*(insn + 1) & OP_RT_RA_MASK) == ADDI_R2_R2))
171 return (ssize_t)(insn + 2) - base;
172 else
173 return (uintptr_t)addr - base;
174}
175
176#else
177
178ssize_t get_uprobe_offset(const void *addr, ssize_t base)
179{
180 return (uintptr_t)addr - base;
181}
182
183#endif
184
185ssize_t get_base_addr(void)
186{
187 size_t start, offset;
188 char buf[256];
189 FILE *f;
190
191 f = fopen("/proc/self/maps", "r");
192 if (!f)
193 return -errno;
194
195 while (fscanf(f, "%zx-%*x %s %zx %*[^\n]\n",
196 &start, buf, &offset) == 3) {
197 if (strcmp(buf, "r-xp") == 0) {
198 fclose(f);
199 return start - offset;
200 }
201 }
202
203 fclose(f);
204 return -EINVAL;
205}
206
207ssize_t get_rel_offset(uintptr_t addr)
208{
209 size_t start, end, offset;
210 char buf[256];
211 FILE *f;
212
213 f = fopen("/proc/self/maps", "r");
214 if (!f)
215 return -errno;
216
217 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &offset) == 4) {
218 if (addr >= start && addr < end) {
219 fclose(f);
220 return (size_t)addr - start + offset;
221 }
222 }
223
224 fclose(f);
225 return -EINVAL;
226}
227