| .. | .. |
|---|
| 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 | } |
|---|