aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/selftests/bpf/trace_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/selftests/bpf/trace_helpers.c')
-rw-r--r--tools/testing/selftests/bpf/trace_helpers.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/tools/testing/selftests/bpf/trace_helpers.c b/tools/testing/selftests/bpf/trace_helpers.c
new file mode 100644
index 000000000000..ad025bd75f1c
--- /dev/null
+++ b/tools/testing/selftests/bpf/trace_helpers.c
@@ -0,0 +1,180 @@
1// SPDX-License-Identifier: GPL-2.0
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <assert.h>
6#include <errno.h>
7#include <poll.h>
8#include <unistd.h>
9#include <linux/perf_event.h>
10#include <sys/mman.h>
11#include "trace_helpers.h"
12
13#define MAX_SYMS 300000
14static struct ksym syms[MAX_SYMS];
15static int sym_cnt;
16
17static int ksym_cmp(const void *p1, const void *p2)
18{
19 return ((struct ksym *)p1)->addr - ((struct ksym *)p2)->addr;
20}
21
22int load_kallsyms(void)
23{
24 FILE *f = fopen("/proc/kallsyms", "r");
25 char func[256], buf[256];
26 char symbol;
27 void *addr;
28 int i = 0;
29
30 if (!f)
31 return -ENOENT;
32
33 while (!feof(f)) {
34 if (!fgets(buf, sizeof(buf), f))
35 break;
36 if (sscanf(buf, "%p %c %s", &addr, &symbol, func) != 3)
37 break;
38 if (!addr)
39 continue;
40 syms[i].addr = (long) addr;
41 syms[i].name = strdup(func);
42 i++;
43 }
44 sym_cnt = i;
45 qsort(syms, sym_cnt, sizeof(struct ksym), ksym_cmp);
46 return 0;
47}
48
49struct ksym *ksym_search(long key)
50{
51 int start = 0, end = sym_cnt;
52 int result;
53
54 while (start < end) {
55 size_t mid = start + (end - start) / 2;
56
57 result = key - syms[mid].addr;
58 if (result < 0)
59 end = mid;
60 else if (result > 0)
61 start = mid + 1;
62 else
63 return &syms[mid];
64 }
65
66 if (start >= 1 && syms[start - 1].addr < key &&
67 key < syms[start].addr)
68 /* valid ksym */
69 return &syms[start - 1];
70
71 /* out of range. return _stext */
72 return &syms[0];
73}
74
75static int page_size;
76static int page_cnt = 8;
77static volatile struct perf_event_mmap_page *header;
78
79int perf_event_mmap(int fd)
80{
81 void *base;
82 int mmap_size;
83
84 page_size = getpagesize();
85 mmap_size = page_size * (page_cnt + 1);
86
87 base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
88 if (base == MAP_FAILED) {
89 printf("mmap err\n");
90 return -1;
91 }
92
93 header = base;
94 return 0;
95}
96
97static int perf_event_poll(int fd)
98{
99 struct pollfd pfd = { .fd = fd, .events = POLLIN };
100
101 return poll(&pfd, 1, 1000);
102}
103
104struct perf_event_sample {
105 struct perf_event_header header;
106 __u32 size;
107 char data[];
108};
109
110static int perf_event_read(perf_event_print_fn fn)
111{
112 __u64 data_tail = header->data_tail;
113 __u64 data_head = header->data_head;
114 __u64 buffer_size = page_cnt * page_size;
115 void *base, *begin, *end;
116 char buf[256];
117 int ret;
118
119 asm volatile("" ::: "memory"); /* in real code it should be smp_rmb() */
120 if (data_head == data_tail)
121 return PERF_EVENT_CONT;
122
123 base = ((char *)header) + page_size;
124
125 begin = base + data_tail % buffer_size;
126 end = base + data_head % buffer_size;
127
128 while (begin != end) {
129 struct perf_event_sample *e;
130
131 e = begin;
132 if (begin + e->header.size > base + buffer_size) {
133 long len = base + buffer_size - begin;
134
135 assert(len < e->header.size);
136 memcpy(buf, begin, len);
137 memcpy(buf + len, base, e->header.size - len);
138 e = (void *) buf;
139 begin = base + e->header.size - len;
140 } else if (begin + e->header.size == base + buffer_size) {
141 begin = base;
142 } else {
143 begin += e->header.size;
144 }
145
146 if (e->header.type == PERF_RECORD_SAMPLE) {
147 ret = fn(e->data, e->size);
148 if (ret != PERF_EVENT_CONT)
149 return ret;
150 } else if (e->header.type == PERF_RECORD_LOST) {
151 struct {
152 struct perf_event_header header;
153 __u64 id;
154 __u64 lost;
155 } *lost = (void *) e;
156 printf("lost %lld events\n", lost->lost);
157 } else {
158 printf("unknown event type=%d size=%d\n",
159 e->header.type, e->header.size);
160 }
161 }
162
163 __sync_synchronize(); /* smp_mb() */
164 header->data_tail = data_head;
165 return PERF_EVENT_CONT;
166}
167
168int perf_event_poller(int fd, perf_event_print_fn output_fn)
169{
170 int ret;
171
172 for (;;) {
173 perf_event_poll(fd);
174 ret = perf_event_read(output_fn);
175 if (ret != PERF_EVENT_CONT)
176 return ret;
177 }
178
179 return PERF_EVENT_DONE;
180}