xref: /aosp_15_r20/external/bcc/libbpf-tools/compat.c (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
2 /* Copyright (c) 2022 Hengqi Chen */
3 
4 #include "compat.h"
5 #include "trace_helpers.h"
6 #include <stdlib.h>
7 #include <errno.h>
8 #include <bpf/libbpf.h>
9 
10 #define PERF_BUFFER_PAGES	64
11 
12 struct bpf_buffer {
13 	struct bpf_map *events;
14 	void *inner;
15 	bpf_buffer_sample_fn fn;
16 	void *ctx;
17 	int type;
18 };
19 
perfbuf_sample_fn(void * ctx,int cpu,void * data,__u32 size)20 static void perfbuf_sample_fn(void *ctx, int cpu, void *data, __u32 size)
21 {
22 	struct bpf_buffer *buffer = ctx;
23 	bpf_buffer_sample_fn fn;
24 
25 	fn = buffer->fn;
26 	if (!fn)
27 		return;
28 
29 	(void)fn(buffer->ctx, data, size);
30 }
31 
bpf_buffer__new(struct bpf_map * events,struct bpf_map * heap)32 struct bpf_buffer *bpf_buffer__new(struct bpf_map *events, struct bpf_map *heap)
33 {
34 	struct bpf_buffer *buffer;
35 	bool use_ringbuf;
36 	int type;
37 
38 	use_ringbuf = probe_ringbuf();
39 	if (use_ringbuf) {
40 		bpf_map__set_autocreate(heap, false);
41 		type = BPF_MAP_TYPE_RINGBUF;
42 	} else {
43 		bpf_map__set_type(events, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
44 		bpf_map__set_key_size(events, sizeof(int));
45 		bpf_map__set_value_size(events, sizeof(int));
46 		type = BPF_MAP_TYPE_PERF_EVENT_ARRAY;
47 	}
48 
49 	buffer = calloc(1, sizeof(*buffer));
50 	if (!buffer) {
51 		errno = ENOMEM;
52 		return NULL;
53 	}
54 
55 	buffer->events = events;
56 	buffer->type = type;
57 	return buffer;
58 }
59 
bpf_buffer__open(struct bpf_buffer * buffer,bpf_buffer_sample_fn sample_cb,bpf_buffer_lost_fn lost_cb,void * ctx)60 int bpf_buffer__open(struct bpf_buffer *buffer, bpf_buffer_sample_fn sample_cb,
61 		     bpf_buffer_lost_fn lost_cb, void *ctx)
62 {
63 	int fd, type;
64 	void *inner;
65 
66 	fd = bpf_map__fd(buffer->events);
67 	type = buffer->type;
68 
69 	switch (type) {
70 	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
71 		buffer->fn = sample_cb;
72 		buffer->ctx = ctx;
73 		inner = perf_buffer__new(fd, PERF_BUFFER_PAGES, perfbuf_sample_fn, lost_cb, buffer, NULL);
74 		break;
75 	case BPF_MAP_TYPE_RINGBUF:
76 		inner = ring_buffer__new(fd, sample_cb, ctx, NULL);
77 		break;
78 	default:
79 		return 0;
80 	}
81 
82 	if (!inner)
83 		return -errno;
84 
85 	buffer->inner = inner;
86 	return 0;
87 }
88 
bpf_buffer__poll(struct bpf_buffer * buffer,int timeout_ms)89 int bpf_buffer__poll(struct bpf_buffer *buffer, int timeout_ms)
90 {
91 	switch (buffer->type) {
92 	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
93 		return perf_buffer__poll(buffer->inner, timeout_ms);
94 	case BPF_MAP_TYPE_RINGBUF:
95 		return ring_buffer__poll(buffer->inner, timeout_ms);
96 	default:
97 		return -EINVAL;
98 	}
99 }
100 
bpf_buffer__free(struct bpf_buffer * buffer)101 void bpf_buffer__free(struct bpf_buffer *buffer)
102 {
103 	if (!buffer)
104 		return;
105 
106 	switch (buffer->type) {
107 	case BPF_MAP_TYPE_PERF_EVENT_ARRAY:
108 		perf_buffer__free(buffer->inner);
109 		break;
110 	case BPF_MAP_TYPE_RINGBUF:
111 		ring_buffer__free(buffer->inner);
112 		break;
113 	}
114 	free(buffer);
115 }
116