1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2018 Facebook
3 
4 #include <linux/bpf.h>
5 #include "bpf_helpers.h"
6 
7 #ifndef PERF_MAX_STACK_DEPTH
8 #define PERF_MAX_STACK_DEPTH         127
9 #endif
10 
11 struct {
12 	__u32 type;
13 	__u32 max_entries;
14 	__u32 *key;
15 	__u32 *value;
16 } control_map SEC(".maps") = {
17 	.type = BPF_MAP_TYPE_ARRAY,
18 	.max_entries = 1,
19 };
20 
21 struct {
22 	__u32 type;
23 	__u32 max_entries;
24 	__u32 *key;
25 	__u32 *value;
26 } stackid_hmap SEC(".maps") = {
27 	.type = BPF_MAP_TYPE_HASH,
28 	.max_entries = 16384,
29 };
30 
31 typedef struct bpf_stack_build_id stack_trace_t[PERF_MAX_STACK_DEPTH];
32 
33 struct {
34 	__u32 type;
35 	__u32 max_entries;
36 	__u32 map_flags;
37 	__u32 key_size;
38 	__u32 value_size;
39 } stackmap SEC(".maps") = {
40 	.type = BPF_MAP_TYPE_STACK_TRACE,
41 	.max_entries = 128,
42 	.map_flags = BPF_F_STACK_BUILD_ID,
43 	.key_size = sizeof(__u32),
44 	.value_size = sizeof(stack_trace_t),
45 };
46 
47 struct {
48 	__u32 type;
49 	__u32 max_entries;
50 	__u32 *key;
51 	/* there seems to be a bug in kernel not handling typedef properly */
52 	struct bpf_stack_build_id (*value)[PERF_MAX_STACK_DEPTH];
53 } stack_amap SEC(".maps") = {
54 	.type = BPF_MAP_TYPE_ARRAY,
55 	.max_entries = 128,
56 };
57 
58 /* taken from /sys/kernel/debug/tracing/events/random/urandom_read/format */
59 struct random_urandom_args {
60 	unsigned long long pad;
61 	int got_bits;
62 	int pool_left;
63 	int input_left;
64 };
65 
66 SEC("tracepoint/random/urandom_read")
67 int oncpu(struct random_urandom_args *args)
68 {
69 	__u32 max_len = sizeof(struct bpf_stack_build_id)
70 			* PERF_MAX_STACK_DEPTH;
71 	__u32 key = 0, val = 0, *value_p;
72 	void *stack_p;
73 
74 	value_p = bpf_map_lookup_elem(&control_map, &key);
75 	if (value_p && *value_p)
76 		return 0; /* skip if non-zero *value_p */
77 
78 	/* The size of stackmap and stackid_hmap should be the same */
79 	key = bpf_get_stackid(args, &stackmap, BPF_F_USER_STACK);
80 	if ((int)key >= 0) {
81 		bpf_map_update_elem(&stackid_hmap, &key, &val, 0);
82 		stack_p = bpf_map_lookup_elem(&stack_amap, &key);
83 		if (stack_p)
84 			bpf_get_stack(args, stack_p, max_len,
85 				      BPF_F_USER_STACK | BPF_F_USER_BUILD_ID);
86 	}
87 
88 	return 0;
89 }
90 
91 char _license[] SEC("license") = "GPL";
92 __u32 _version SEC("version") = 1; /* ignored by tracepoints, required by libbpf.a */
93