xref: /linux/tools/testing/selftests/bpf/progs/verifier_subprog_insn_stats.c (revision 5a8cd539ac19f7a68e68e1d25ef9ca2ff55b8500)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #include <vmlinux.h>
4 #include <bpf/bpf_helpers.h>
5 #include "bpf_misc.h"
6 
7 struct timer_value {
8 	struct bpf_timer timer;
9 };
10 
11 struct {
12 	__uint(type, BPF_MAP_TYPE_ARRAY);
13 	__uint(max_entries, 1);
14 	__type(key, __u32);
15 	__type(value, struct timer_value);
16 } timer_map SEC(".maps");
17 
18 SEC("?raw_tp")
19 __success __log_level(4)
20 __msg("subprog 0 (stats_main_only) main insns_self 2 insns_total 2 stack 0")
21 __msg("processed 2 insns")
stats_main_only(void)22 __naked int stats_main_only(void)
23 {
24 	asm volatile (
25 		"r0 = 0;"
26 		"exit;"
27 	);
28 }
29 
30 __naked __noinline __used
stats_chain_leaf(void)31 static int stats_chain_leaf(void)
32 {
33 	asm volatile (
34 		"r0 = 0;"
35 		"exit;"
36 	);
37 }
38 
39 __naked __noinline __used
stats_chain_parent(void)40 static int stats_chain_parent(void)
41 {
42 	asm volatile (
43 		"call stats_chain_leaf;"
44 		"exit;"
45 	);
46 }
47 
48 SEC("?raw_tp")
49 __success __log_level(4)
50 /*
51  * self: 2 + 2 + 2 = 6
52  * totals: leaf 2, parent 2 + 2 = 4, main 2 + 4 = 6
53  */
54 __msg("subprog 0 (stats_static_chain) main insns_self 2 insns_total 6 stack 0")
55 __msg("subprog {{[0-9]+}} (stats_chain_parent) static insns_self 2 insns_total 4 stack 0")
56 __msg("subprog {{[0-9]+}} (stats_chain_leaf) static insns_self 2 insns_total 2 stack 0")
57 __msg("processed 6 insns")
stats_static_chain(void)58 __naked int stats_static_chain(void)
59 {
60 	asm volatile (
61 		"call stats_chain_parent;"
62 		"exit;"
63 	);
64 }
65 
66 __naked __noinline __used
stats_shared_leaf(void)67 static int stats_shared_leaf(void)
68 {
69 	asm volatile (
70 		"r0 = 0;"
71 		"exit;"
72 	);
73 }
74 
75 __naked __noinline __used
stats_global_root(void)76 int stats_global_root(void)
77 {
78 	asm volatile (
79 		"call stats_shared_leaf;"
80 		"exit;"
81 	);
82 }
83 
84 SEC("?raw_tp")
85 __success __log_level(4)
86 /*
87  * stats_shared_leaf is explored once under each independent root.
88  * self: main 3 + leaf 4 + global 2 = 9
89  * root totals: main 5 + global 4 = 9
90  */
91 __msg("subprog 0 (stats_shared_roots) main insns_self 3 insns_total 5 stack 0")
92 __msg("subprog {{[0-9]+}} (stats_shared_leaf) static insns_self 4 insns_total 4 stack 0")
93 __msg("subprog {{[0-9]+}} (stats_global_root) global insns_self 2 insns_total 4 stack 0")
94 __msg("processed 9 insns")
stats_shared_roots(void)95 __naked int stats_shared_roots(void)
96 {
97 	asm volatile (
98 		"call stats_shared_leaf;"
99 		"call stats_global_root;"
100 		"exit;"
101 	);
102 }
103 
104 __noinline __used
stats_async_leaf(void * map,__u32 * key,struct bpf_timer * timer)105 static int stats_async_leaf(void *map, __u32 *key, struct bpf_timer *timer)
106 {
107 	return 0;
108 }
109 
110 __noinline __used
stats_async_schedule(struct bpf_map * map,__u32 * key,struct timer_value * value,void * ctx)111 static __u64 stats_async_schedule(struct bpf_map *map, __u32 *key,
112 				  struct timer_value *value, void *ctx)
113 {
114 	asm volatile (
115 		"r1 = %[timer];"
116 		"r2 = %[stats_async_leaf];"
117 		"call %[bpf_timer_set_callback];"
118 		:
119 		: [timer] "r" (value),
120 		  __imm_ptr(stats_async_leaf),
121 		  __imm(bpf_timer_set_callback)
122 		: __clobber_common
123 	);
124 	return 0;
125 }
126 
127 SEC("?raw_tp")
128 __success __log_level(4)
129 /*
130  * self: 9 + 7 + 2 = 18
131  * totals: leaf 2, scheduler 7, main root 18
132  */
133 __msg("subprog 0 (stats_async_direct) main insns_self 9 insns_total 18 stack 0")
134 __msg("subprog {{[0-9]+}} (stats_async_schedule) static insns_self 7 insns_total 7 stack 0")
135 __msg("subprog {{[0-9]+}} (stats_async_leaf) static insns_self 2 insns_total 2 stack 0")
136 __msg("processed 18 insns")
stats_async_direct(void)137 __naked int stats_async_direct(void)
138 {
139 	asm volatile (
140 		"r1 = %[timer_map] ll;"
141 		"r2 = %[stats_async_schedule];"
142 		"r3 = 0;"
143 		"r4 = 0;"
144 		"call %[bpf_for_each_map_elem];"
145 		"r0 = 0;"
146 		"exit;"
147 		:
148 		: __imm_addr(timer_map),
149 		  __imm_ptr(stats_async_schedule),
150 		  __imm(bpf_for_each_map_elem)
151 		: __clobber_common
152 	);
153 }
154 
155 __noinline __used
stats_async_nested_leaf(void * map,__u32 * key,struct bpf_timer * timer)156 static int stats_async_nested_leaf(void *map, __u32 *key, struct bpf_timer *timer)
157 {
158 	return 0;
159 }
160 
161 __noinline __used
stats_async_outer(void * map,__u32 * key,struct bpf_timer * timer)162 static int stats_async_outer(void *map, __u32 *key, struct bpf_timer *timer)
163 {
164 	asm volatile (
165 		"r1 = %[timer];"
166 		"r2 = %[stats_async_nested_leaf];"
167 		"call %[bpf_timer_set_callback];"
168 		:
169 		: [timer] "r" (timer),
170 		  __imm_ptr(stats_async_nested_leaf),
171 		  __imm(bpf_timer_set_callback)
172 		: __clobber_common
173 	);
174 	return 0;
175 }
176 
177 __noinline __used
stats_async_nested_schedule(struct bpf_map * map,__u32 * key,struct timer_value * value,void * ctx)178 static __u64 stats_async_nested_schedule(struct bpf_map *map, __u32 *key,
179 					 struct timer_value *value, void *ctx)
180 {
181 	asm volatile (
182 		"r1 = %[timer];"
183 		"r2 = %[stats_async_outer];"
184 		"call %[bpf_timer_set_callback];"
185 		:
186 		: [timer] "r" (value),
187 		  __imm_ptr(stats_async_outer),
188 		  __imm(bpf_timer_set_callback)
189 		: __clobber_common
190 	);
191 	return 0;
192 }
193 
194 SEC("?raw_tp")
195 __success __log_level(4)
196 /*
197  * self: 9 + 7 + 7 + 2 = 25
198  * totals: leaf 2, outer 7, scheduler 7, main root 25
199  */
200 __msg("subprog 0 (stats_async_nested) main insns_self 9 insns_total 25 stack 0")
201 __msg("subprog {{[0-9]+}} (stats_async_nested_schedule) static insns_self 7 insns_total 7 stack 0")
202 __msg("subprog {{[0-9]+}} (stats_async_outer) static insns_self 7 insns_total 7 stack 0")
203 __msg("subprog {{[0-9]+}} (stats_async_nested_leaf) static insns_self 2 insns_total 2 stack 0")
204 __msg("processed 25 insns")
stats_async_nested(void)205 __naked int stats_async_nested(void)
206 {
207 	asm volatile (
208 		"r1 = %[timer_map] ll;"
209 		"r2 = %[stats_async_nested_schedule];"
210 		"r3 = 0;"
211 		"r4 = 0;"
212 		"call %[bpf_for_each_map_elem];"
213 		"r0 = 0;"
214 		"exit;"
215 		:
216 		: __imm_addr(timer_map),
217 		  __imm_ptr(stats_async_nested_schedule),
218 		  __imm(bpf_for_each_map_elem)
219 		: __clobber_common
220 	);
221 }
222 
223 char _license[] SEC("license") = "GPL";
224