.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* Copyright (c) 2016 Facebook |
---|
2 | | - * |
---|
3 | | - * This program is free software; you can redistribute it and/or |
---|
4 | | - * modify it under the terms of version 2 of the GNU General Public |
---|
5 | | - * License as published by the Free Software Foundation. |
---|
6 | 3 | */ |
---|
7 | 4 | #include <stdio.h> |
---|
8 | 5 | #include <unistd.h> |
---|
9 | 6 | #include <stdlib.h> |
---|
10 | 7 | #include <stdbool.h> |
---|
11 | 8 | #include <string.h> |
---|
12 | | -#include <fcntl.h> |
---|
13 | | -#include <poll.h> |
---|
14 | | -#include <sys/ioctl.h> |
---|
15 | 9 | #include <linux/perf_event.h> |
---|
16 | 10 | #include <linux/bpf.h> |
---|
17 | 11 | #include <signal.h> |
---|
18 | | -#include <assert.h> |
---|
19 | 12 | #include <errno.h> |
---|
20 | 13 | #include <sys/resource.h> |
---|
21 | | -#include "libbpf.h" |
---|
22 | | -#include "bpf_load.h" |
---|
| 14 | +#include <bpf/bpf.h> |
---|
| 15 | +#include <bpf/libbpf.h> |
---|
23 | 16 | #include "perf-sys.h" |
---|
24 | 17 | #include "trace_helpers.h" |
---|
25 | 18 | |
---|
26 | 19 | #define SAMPLE_FREQ 50 |
---|
27 | 20 | |
---|
| 21 | +static int pid; |
---|
| 22 | +/* counts, stackmap */ |
---|
| 23 | +static int map_fd[2]; |
---|
| 24 | +struct bpf_program *prog; |
---|
28 | 25 | static bool sys_read_seen, sys_write_seen; |
---|
29 | 26 | |
---|
30 | 27 | static void print_ksym(__u64 addr) |
---|
.. | .. |
---|
34 | 31 | if (!addr) |
---|
35 | 32 | return; |
---|
36 | 33 | sym = ksym_search(addr); |
---|
| 34 | + if (!sym) { |
---|
| 35 | + printf("ksym not found. Is kallsyms loaded?\n"); |
---|
| 36 | + return; |
---|
| 37 | + } |
---|
| 38 | + |
---|
37 | 39 | printf("%s;", sym->name); |
---|
38 | 40 | if (!strstr(sym->name, "sys_read")) |
---|
39 | 41 | sys_read_seen = true; |
---|
.. | .. |
---|
89 | 91 | } |
---|
90 | 92 | } |
---|
91 | 93 | |
---|
92 | | -static void int_exit(int sig) |
---|
| 94 | +static void err_exit(int err) |
---|
93 | 95 | { |
---|
94 | | - kill(0, SIGKILL); |
---|
95 | | - exit(0); |
---|
| 96 | + kill(pid, SIGKILL); |
---|
| 97 | + exit(err); |
---|
96 | 98 | } |
---|
97 | 99 | |
---|
98 | 100 | static void print_stacks(void) |
---|
.. | .. |
---|
100 | 102 | struct key_t key = {}, next_key; |
---|
101 | 103 | __u64 value; |
---|
102 | 104 | __u32 stackid = 0, next_id; |
---|
103 | | - int fd = map_fd[0], stack_map = map_fd[1]; |
---|
| 105 | + int error = 1, fd = map_fd[0], stack_map = map_fd[1]; |
---|
104 | 106 | |
---|
105 | 107 | sys_read_seen = sys_write_seen = false; |
---|
106 | 108 | while (bpf_map_get_next_key(fd, &key, &next_key) == 0) { |
---|
.. | .. |
---|
112 | 114 | printf("\n"); |
---|
113 | 115 | if (!sys_read_seen || !sys_write_seen) { |
---|
114 | 116 | printf("BUG kernel stack doesn't contain sys_read() and sys_write()\n"); |
---|
115 | | - int_exit(0); |
---|
| 117 | + err_exit(error); |
---|
116 | 118 | } |
---|
117 | 119 | |
---|
118 | 120 | /* clear stack map */ |
---|
.. | .. |
---|
134 | 136 | |
---|
135 | 137 | static void test_perf_event_all_cpu(struct perf_event_attr *attr) |
---|
136 | 138 | { |
---|
137 | | - int nr_cpus = sysconf(_SC_NPROCESSORS_CONF); |
---|
138 | | - int *pmu_fd = malloc(nr_cpus * sizeof(int)); |
---|
139 | | - int i, error = 0; |
---|
| 139 | + int nr_cpus = sysconf(_SC_NPROCESSORS_ONLN); |
---|
| 140 | + struct bpf_link **links = calloc(nr_cpus, sizeof(struct bpf_link *)); |
---|
| 141 | + int i, pmu_fd, error = 1; |
---|
| 142 | + |
---|
| 143 | + if (!links) { |
---|
| 144 | + printf("malloc of links failed\n"); |
---|
| 145 | + goto err; |
---|
| 146 | + } |
---|
140 | 147 | |
---|
141 | 148 | /* system wide perf event, no need to inherit */ |
---|
142 | 149 | attr->inherit = 0; |
---|
143 | 150 | |
---|
144 | 151 | /* open perf_event on all cpus */ |
---|
145 | 152 | for (i = 0; i < nr_cpus; i++) { |
---|
146 | | - pmu_fd[i] = sys_perf_event_open(attr, -1, i, -1, 0); |
---|
147 | | - if (pmu_fd[i] < 0) { |
---|
| 153 | + pmu_fd = sys_perf_event_open(attr, -1, i, -1, 0); |
---|
| 154 | + if (pmu_fd < 0) { |
---|
148 | 155 | printf("sys_perf_event_open failed\n"); |
---|
149 | | - error = 1; |
---|
150 | 156 | goto all_cpu_err; |
---|
151 | 157 | } |
---|
152 | | - assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_SET_BPF, prog_fd[0]) == 0); |
---|
153 | | - assert(ioctl(pmu_fd[i], PERF_EVENT_IOC_ENABLE) == 0); |
---|
| 158 | + links[i] = bpf_program__attach_perf_event(prog, pmu_fd); |
---|
| 159 | + if (libbpf_get_error(links[i])) { |
---|
| 160 | + printf("bpf_program__attach_perf_event failed\n"); |
---|
| 161 | + links[i] = NULL; |
---|
| 162 | + close(pmu_fd); |
---|
| 163 | + goto all_cpu_err; |
---|
| 164 | + } |
---|
154 | 165 | } |
---|
155 | 166 | |
---|
156 | | - if (generate_load() < 0) { |
---|
157 | | - error = 1; |
---|
| 167 | + if (generate_load() < 0) |
---|
158 | 168 | goto all_cpu_err; |
---|
159 | | - } |
---|
| 169 | + |
---|
160 | 170 | print_stacks(); |
---|
| 171 | + error = 0; |
---|
161 | 172 | all_cpu_err: |
---|
162 | | - for (i--; i >= 0; i--) { |
---|
163 | | - ioctl(pmu_fd[i], PERF_EVENT_IOC_DISABLE); |
---|
164 | | - close(pmu_fd[i]); |
---|
165 | | - } |
---|
166 | | - free(pmu_fd); |
---|
| 173 | + for (i--; i >= 0; i--) |
---|
| 174 | + bpf_link__destroy(links[i]); |
---|
| 175 | +err: |
---|
| 176 | + free(links); |
---|
167 | 177 | if (error) |
---|
168 | | - int_exit(0); |
---|
| 178 | + err_exit(error); |
---|
169 | 179 | } |
---|
170 | 180 | |
---|
171 | 181 | static void test_perf_event_task(struct perf_event_attr *attr) |
---|
172 | 182 | { |
---|
173 | | - int pmu_fd, error = 0; |
---|
| 183 | + struct bpf_link *link = NULL; |
---|
| 184 | + int pmu_fd, error = 1; |
---|
174 | 185 | |
---|
175 | 186 | /* per task perf event, enable inherit so the "dd ..." command can be traced properly. |
---|
176 | 187 | * Enabling inherit will cause bpf_perf_prog_read_time helper failure. |
---|
.. | .. |
---|
181 | 192 | pmu_fd = sys_perf_event_open(attr, 0, -1, -1, 0); |
---|
182 | 193 | if (pmu_fd < 0) { |
---|
183 | 194 | printf("sys_perf_event_open failed\n"); |
---|
184 | | - int_exit(0); |
---|
185 | | - } |
---|
186 | | - assert(ioctl(pmu_fd, PERF_EVENT_IOC_SET_BPF, prog_fd[0]) == 0); |
---|
187 | | - assert(ioctl(pmu_fd, PERF_EVENT_IOC_ENABLE) == 0); |
---|
188 | | - |
---|
189 | | - if (generate_load() < 0) { |
---|
190 | | - error = 1; |
---|
191 | 195 | goto err; |
---|
192 | 196 | } |
---|
| 197 | + link = bpf_program__attach_perf_event(prog, pmu_fd); |
---|
| 198 | + if (libbpf_get_error(link)) { |
---|
| 199 | + printf("bpf_program__attach_perf_event failed\n"); |
---|
| 200 | + link = NULL; |
---|
| 201 | + close(pmu_fd); |
---|
| 202 | + goto err; |
---|
| 203 | + } |
---|
| 204 | + |
---|
| 205 | + if (generate_load() < 0) |
---|
| 206 | + goto err; |
---|
| 207 | + |
---|
193 | 208 | print_stacks(); |
---|
| 209 | + error = 0; |
---|
194 | 210 | err: |
---|
195 | | - ioctl(pmu_fd, PERF_EVENT_IOC_DISABLE); |
---|
196 | | - close(pmu_fd); |
---|
| 211 | + bpf_link__destroy(link); |
---|
197 | 212 | if (error) |
---|
198 | | - int_exit(0); |
---|
| 213 | + err_exit(error); |
---|
199 | 214 | } |
---|
200 | 215 | |
---|
201 | 216 | static void test_bpf_perf_event(void) |
---|
.. | .. |
---|
280 | 295 | int main(int argc, char **argv) |
---|
281 | 296 | { |
---|
282 | 297 | struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY}; |
---|
| 298 | + struct bpf_object *obj = NULL; |
---|
283 | 299 | char filename[256]; |
---|
| 300 | + int error = 1; |
---|
284 | 301 | |
---|
285 | 302 | snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]); |
---|
286 | 303 | setrlimit(RLIMIT_MEMLOCK, &r); |
---|
287 | 304 | |
---|
288 | | - signal(SIGINT, int_exit); |
---|
289 | | - signal(SIGTERM, int_exit); |
---|
| 305 | + signal(SIGINT, err_exit); |
---|
| 306 | + signal(SIGTERM, err_exit); |
---|
290 | 307 | |
---|
291 | 308 | if (load_kallsyms()) { |
---|
292 | 309 | printf("failed to process /proc/kallsyms\n"); |
---|
293 | | - return 1; |
---|
| 310 | + goto cleanup; |
---|
294 | 311 | } |
---|
295 | 312 | |
---|
296 | | - if (load_bpf_file(filename)) { |
---|
297 | | - printf("%s", bpf_log_buf); |
---|
298 | | - return 2; |
---|
| 313 | + obj = bpf_object__open_file(filename, NULL); |
---|
| 314 | + if (libbpf_get_error(obj)) { |
---|
| 315 | + printf("opening BPF object file failed\n"); |
---|
| 316 | + obj = NULL; |
---|
| 317 | + goto cleanup; |
---|
299 | 318 | } |
---|
300 | 319 | |
---|
301 | | - if (fork() == 0) { |
---|
| 320 | + prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); |
---|
| 321 | + if (!prog) { |
---|
| 322 | + printf("finding a prog in obj file failed\n"); |
---|
| 323 | + goto cleanup; |
---|
| 324 | + } |
---|
| 325 | + |
---|
| 326 | + /* load BPF program */ |
---|
| 327 | + if (bpf_object__load(obj)) { |
---|
| 328 | + printf("loading BPF object file failed\n"); |
---|
| 329 | + goto cleanup; |
---|
| 330 | + } |
---|
| 331 | + |
---|
| 332 | + map_fd[0] = bpf_object__find_map_fd_by_name(obj, "counts"); |
---|
| 333 | + map_fd[1] = bpf_object__find_map_fd_by_name(obj, "stackmap"); |
---|
| 334 | + if (map_fd[0] < 0 || map_fd[1] < 0) { |
---|
| 335 | + printf("finding a counts/stackmap map in obj file failed\n"); |
---|
| 336 | + goto cleanup; |
---|
| 337 | + } |
---|
| 338 | + |
---|
| 339 | + pid = fork(); |
---|
| 340 | + if (pid == 0) { |
---|
302 | 341 | read_trace_pipe(); |
---|
303 | 342 | return 0; |
---|
| 343 | + } else if (pid == -1) { |
---|
| 344 | + printf("couldn't spawn process\n"); |
---|
| 345 | + goto cleanup; |
---|
304 | 346 | } |
---|
| 347 | + |
---|
305 | 348 | test_bpf_perf_event(); |
---|
306 | | - int_exit(0); |
---|
307 | | - return 0; |
---|
| 349 | + error = 0; |
---|
| 350 | + |
---|
| 351 | +cleanup: |
---|
| 352 | + bpf_object__close(obj); |
---|
| 353 | + err_exit(error); |
---|
308 | 354 | } |
---|