xref: /linux/tools/testing/selftests/bpf/progs/verifier_subprog_topo.c (revision 0fc8f6200d2313278fbf4539bbab74677c685531)
1*427c07ddSAlexei Starovoitov // SPDX-License-Identifier: GPL-2.0
2*427c07ddSAlexei Starovoitov /* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
3*427c07ddSAlexei Starovoitov 
4*427c07ddSAlexei Starovoitov #include <linux/bpf.h>
5*427c07ddSAlexei Starovoitov #include <bpf/bpf_helpers.h>
6*427c07ddSAlexei Starovoitov #include "bpf_misc.h"
7*427c07ddSAlexei Starovoitov 
8*427c07ddSAlexei Starovoitov /* linear chain main -> A -> B */
9*427c07ddSAlexei Starovoitov __naked __noinline __used
10*427c07ddSAlexei Starovoitov static unsigned long linear_b(void)
11*427c07ddSAlexei Starovoitov {
12*427c07ddSAlexei Starovoitov 	asm volatile (
13*427c07ddSAlexei Starovoitov 		"r0 = 42;"
14*427c07ddSAlexei Starovoitov 		"exit;"
15*427c07ddSAlexei Starovoitov 	);
16*427c07ddSAlexei Starovoitov }
17*427c07ddSAlexei Starovoitov 
18*427c07ddSAlexei Starovoitov __naked __noinline __used
19*427c07ddSAlexei Starovoitov static unsigned long linear_a(void)
20*427c07ddSAlexei Starovoitov {
21*427c07ddSAlexei Starovoitov 	asm volatile (
22*427c07ddSAlexei Starovoitov 		"call linear_b;"
23*427c07ddSAlexei Starovoitov 		"exit;"
24*427c07ddSAlexei Starovoitov 	);
25*427c07ddSAlexei Starovoitov }
26*427c07ddSAlexei Starovoitov 
27*427c07ddSAlexei Starovoitov SEC("?raw_tp")
28*427c07ddSAlexei Starovoitov __success __log_level(2)
29*427c07ddSAlexei Starovoitov __msg("topo_order[0] = linear_b")
30*427c07ddSAlexei Starovoitov __msg("topo_order[1] = linear_a")
31*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_linear")
32*427c07ddSAlexei Starovoitov __naked int topo_linear(void)
33*427c07ddSAlexei Starovoitov {
34*427c07ddSAlexei Starovoitov 	asm volatile (
35*427c07ddSAlexei Starovoitov 		"call linear_a;"
36*427c07ddSAlexei Starovoitov 		"exit;"
37*427c07ddSAlexei Starovoitov 	);
38*427c07ddSAlexei Starovoitov }
39*427c07ddSAlexei Starovoitov 
40*427c07ddSAlexei Starovoitov /* diamond main -> A, main -> B, A -> C, B -> C */
41*427c07ddSAlexei Starovoitov __naked __noinline __used
42*427c07ddSAlexei Starovoitov static unsigned long diamond_c(void)
43*427c07ddSAlexei Starovoitov {
44*427c07ddSAlexei Starovoitov 	asm volatile (
45*427c07ddSAlexei Starovoitov 		"r0 = 1;"
46*427c07ddSAlexei Starovoitov 		"exit;"
47*427c07ddSAlexei Starovoitov 	);
48*427c07ddSAlexei Starovoitov }
49*427c07ddSAlexei Starovoitov 
50*427c07ddSAlexei Starovoitov __naked __noinline __used
51*427c07ddSAlexei Starovoitov static unsigned long diamond_b(void)
52*427c07ddSAlexei Starovoitov {
53*427c07ddSAlexei Starovoitov 	asm volatile (
54*427c07ddSAlexei Starovoitov 		"call diamond_c;"
55*427c07ddSAlexei Starovoitov 		"exit;"
56*427c07ddSAlexei Starovoitov 	);
57*427c07ddSAlexei Starovoitov }
58*427c07ddSAlexei Starovoitov 
59*427c07ddSAlexei Starovoitov __naked __noinline __used
60*427c07ddSAlexei Starovoitov static unsigned long diamond_a(void)
61*427c07ddSAlexei Starovoitov {
62*427c07ddSAlexei Starovoitov 	asm volatile (
63*427c07ddSAlexei Starovoitov 		"call diamond_c;"
64*427c07ddSAlexei Starovoitov 		"exit;"
65*427c07ddSAlexei Starovoitov 	);
66*427c07ddSAlexei Starovoitov }
67*427c07ddSAlexei Starovoitov 
68*427c07ddSAlexei Starovoitov SEC("?raw_tp")
69*427c07ddSAlexei Starovoitov __success __log_level(2)
70*427c07ddSAlexei Starovoitov __msg("topo_order[0] = diamond_c")
71*427c07ddSAlexei Starovoitov __msg("topo_order[3] = topo_diamond")
72*427c07ddSAlexei Starovoitov __naked int topo_diamond(void)
73*427c07ddSAlexei Starovoitov {
74*427c07ddSAlexei Starovoitov 	asm volatile (
75*427c07ddSAlexei Starovoitov 		"call diamond_a;"
76*427c07ddSAlexei Starovoitov 		"call diamond_b;"
77*427c07ddSAlexei Starovoitov 		"exit;"
78*427c07ddSAlexei Starovoitov 	);
79*427c07ddSAlexei Starovoitov }
80*427c07ddSAlexei Starovoitov 
81*427c07ddSAlexei Starovoitov /* main -> global_a (global) -> static_leaf (static, leaf) */
82*427c07ddSAlexei Starovoitov __naked __noinline __used
83*427c07ddSAlexei Starovoitov static unsigned long static_leaf(void)
84*427c07ddSAlexei Starovoitov {
85*427c07ddSAlexei Starovoitov 	asm volatile (
86*427c07ddSAlexei Starovoitov 		"r0 = 7;"
87*427c07ddSAlexei Starovoitov 		"exit;"
88*427c07ddSAlexei Starovoitov 	);
89*427c07ddSAlexei Starovoitov }
90*427c07ddSAlexei Starovoitov 
91*427c07ddSAlexei Starovoitov __noinline __used
92*427c07ddSAlexei Starovoitov int global_a(int x)
93*427c07ddSAlexei Starovoitov {
94*427c07ddSAlexei Starovoitov 	return static_leaf();
95*427c07ddSAlexei Starovoitov }
96*427c07ddSAlexei Starovoitov 
97*427c07ddSAlexei Starovoitov SEC("?raw_tp")
98*427c07ddSAlexei Starovoitov __success __log_level(2)
99*427c07ddSAlexei Starovoitov __msg("topo_order[0] = static_leaf")
100*427c07ddSAlexei Starovoitov __msg("topo_order[1] = global_a")
101*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_mixed")
102*427c07ddSAlexei Starovoitov __naked int topo_mixed(void)
103*427c07ddSAlexei Starovoitov {
104*427c07ddSAlexei Starovoitov 	asm volatile (
105*427c07ddSAlexei Starovoitov 		"r1 = 0;"
106*427c07ddSAlexei Starovoitov 		"call global_a;"
107*427c07ddSAlexei Starovoitov 		"exit;"
108*427c07ddSAlexei Starovoitov 	);
109*427c07ddSAlexei Starovoitov }
110*427c07ddSAlexei Starovoitov 
111*427c07ddSAlexei Starovoitov /*
112*427c07ddSAlexei Starovoitov  * shared static callee from global and main:
113*427c07ddSAlexei Starovoitov  * main -> shared_leaf (static)
114*427c07ddSAlexei Starovoitov  * main -> global_b (global) -> shared_leaf (static)
115*427c07ddSAlexei Starovoitov  */
116*427c07ddSAlexei Starovoitov __naked __noinline __used
117*427c07ddSAlexei Starovoitov static unsigned long shared_leaf(void)
118*427c07ddSAlexei Starovoitov {
119*427c07ddSAlexei Starovoitov 	asm volatile (
120*427c07ddSAlexei Starovoitov 		"r0 = 99;"
121*427c07ddSAlexei Starovoitov 		"exit;"
122*427c07ddSAlexei Starovoitov 	);
123*427c07ddSAlexei Starovoitov }
124*427c07ddSAlexei Starovoitov 
125*427c07ddSAlexei Starovoitov __noinline __used
126*427c07ddSAlexei Starovoitov int global_b(int x)
127*427c07ddSAlexei Starovoitov {
128*427c07ddSAlexei Starovoitov 	return shared_leaf();
129*427c07ddSAlexei Starovoitov }
130*427c07ddSAlexei Starovoitov 
131*427c07ddSAlexei Starovoitov SEC("?raw_tp")
132*427c07ddSAlexei Starovoitov __success __log_level(2)
133*427c07ddSAlexei Starovoitov __msg("topo_order[0] = shared_leaf")
134*427c07ddSAlexei Starovoitov __msg("topo_order[1] = global_b")
135*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_shared")
136*427c07ddSAlexei Starovoitov __naked int topo_shared(void)
137*427c07ddSAlexei Starovoitov {
138*427c07ddSAlexei Starovoitov 	asm volatile (
139*427c07ddSAlexei Starovoitov 		"call shared_leaf;"
140*427c07ddSAlexei Starovoitov 		"r1 = 0;"
141*427c07ddSAlexei Starovoitov 		"call global_b;"
142*427c07ddSAlexei Starovoitov 		"exit;"
143*427c07ddSAlexei Starovoitov 	);
144*427c07ddSAlexei Starovoitov }
145*427c07ddSAlexei Starovoitov 
146*427c07ddSAlexei Starovoitov /* duplicate calls to the same subprog */
147*427c07ddSAlexei Starovoitov __naked __noinline __used
148*427c07ddSAlexei Starovoitov static unsigned long dup_leaf(void)
149*427c07ddSAlexei Starovoitov {
150*427c07ddSAlexei Starovoitov 	asm volatile (
151*427c07ddSAlexei Starovoitov 		"r0 = 0;"
152*427c07ddSAlexei Starovoitov 		"exit;"
153*427c07ddSAlexei Starovoitov 	);
154*427c07ddSAlexei Starovoitov }
155*427c07ddSAlexei Starovoitov 
156*427c07ddSAlexei Starovoitov SEC("?raw_tp")
157*427c07ddSAlexei Starovoitov __success __log_level(2)
158*427c07ddSAlexei Starovoitov __msg("topo_order[0] = dup_leaf")
159*427c07ddSAlexei Starovoitov __msg("topo_order[1] = topo_dup_calls")
160*427c07ddSAlexei Starovoitov __naked int topo_dup_calls(void)
161*427c07ddSAlexei Starovoitov {
162*427c07ddSAlexei Starovoitov 	asm volatile (
163*427c07ddSAlexei Starovoitov 		"call dup_leaf;"
164*427c07ddSAlexei Starovoitov 		"call dup_leaf;"
165*427c07ddSAlexei Starovoitov 		"exit;"
166*427c07ddSAlexei Starovoitov 	);
167*427c07ddSAlexei Starovoitov }
168*427c07ddSAlexei Starovoitov 
169*427c07ddSAlexei Starovoitov /* main calls bpf_loop() with loop_cb as the callback */
170*427c07ddSAlexei Starovoitov static int loop_cb(int idx, void *ctx)
171*427c07ddSAlexei Starovoitov {
172*427c07ddSAlexei Starovoitov 	return 0;
173*427c07ddSAlexei Starovoitov }
174*427c07ddSAlexei Starovoitov 
175*427c07ddSAlexei Starovoitov SEC("?raw_tp")
176*427c07ddSAlexei Starovoitov __success __log_level(2)
177*427c07ddSAlexei Starovoitov __msg("topo_order[0] = loop_cb")
178*427c07ddSAlexei Starovoitov __msg("topo_order[1] = topo_loop_cb")
179*427c07ddSAlexei Starovoitov int topo_loop_cb(void)
180*427c07ddSAlexei Starovoitov {
181*427c07ddSAlexei Starovoitov 	bpf_loop(1, loop_cb, NULL, 0);
182*427c07ddSAlexei Starovoitov 	return 0;
183*427c07ddSAlexei Starovoitov }
184*427c07ddSAlexei Starovoitov 
185*427c07ddSAlexei Starovoitov /*
186*427c07ddSAlexei Starovoitov  * bpf_loop callback calling another subprog
187*427c07ddSAlexei Starovoitov  * main -> bpf_loop(callback=loop_cb2) -> loop_cb2 -> loop_cb2_leaf
188*427c07ddSAlexei Starovoitov  */
189*427c07ddSAlexei Starovoitov __naked __noinline __used
190*427c07ddSAlexei Starovoitov static unsigned long loop_cb2_leaf(void)
191*427c07ddSAlexei Starovoitov {
192*427c07ddSAlexei Starovoitov 	asm volatile (
193*427c07ddSAlexei Starovoitov 		"r0 = 0;"
194*427c07ddSAlexei Starovoitov 		"exit;"
195*427c07ddSAlexei Starovoitov 	);
196*427c07ddSAlexei Starovoitov }
197*427c07ddSAlexei Starovoitov 
198*427c07ddSAlexei Starovoitov static int loop_cb2(int idx, void *ctx)
199*427c07ddSAlexei Starovoitov {
200*427c07ddSAlexei Starovoitov 	return loop_cb2_leaf();
201*427c07ddSAlexei Starovoitov }
202*427c07ddSAlexei Starovoitov 
203*427c07ddSAlexei Starovoitov SEC("?raw_tp")
204*427c07ddSAlexei Starovoitov __success __log_level(2)
205*427c07ddSAlexei Starovoitov __msg("topo_order[0] = loop_cb2_leaf")
206*427c07ddSAlexei Starovoitov __msg("topo_order[1] = loop_cb2")
207*427c07ddSAlexei Starovoitov __msg("topo_order[2] = topo_loop_cb_chain")
208*427c07ddSAlexei Starovoitov int topo_loop_cb_chain(void)
209*427c07ddSAlexei Starovoitov {
210*427c07ddSAlexei Starovoitov 	bpf_loop(1, loop_cb2, NULL, 0);
211*427c07ddSAlexei Starovoitov 	return 0;
212*427c07ddSAlexei Starovoitov }
213*427c07ddSAlexei Starovoitov 
214*427c07ddSAlexei Starovoitov /* no calls (single subprog) */
215*427c07ddSAlexei Starovoitov SEC("?raw_tp")
216*427c07ddSAlexei Starovoitov __success __log_level(2)
217*427c07ddSAlexei Starovoitov __msg("topo_order[0] = topo_no_calls")
218*427c07ddSAlexei Starovoitov __naked int topo_no_calls(void)
219*427c07ddSAlexei Starovoitov {
220*427c07ddSAlexei Starovoitov 	asm volatile (
221*427c07ddSAlexei Starovoitov 		"r0 = 0;"
222*427c07ddSAlexei Starovoitov 		"exit;"
223*427c07ddSAlexei Starovoitov 	);
224*427c07ddSAlexei Starovoitov }
225*427c07ddSAlexei Starovoitov 
226*427c07ddSAlexei Starovoitov char _license[] SEC("license") = "GPL";
227