13ef3d217SAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
23ef3d217SAndrii Nakryiko /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
33ef3d217SAndrii Nakryiko 
43ef3d217SAndrii Nakryiko #include <errno.h>
53ef3d217SAndrii Nakryiko #include <string.h>
63ef3d217SAndrii Nakryiko #include <linux/bpf.h>
73ef3d217SAndrii Nakryiko #include <bpf/bpf_helpers.h>
83ef3d217SAndrii Nakryiko #include "bpf_misc.h"
93ef3d217SAndrii Nakryiko 
103ef3d217SAndrii Nakryiko #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
113ef3d217SAndrii Nakryiko 
123ef3d217SAndrii Nakryiko int vals[] SEC(".data.vals") = {1, 2, 3, 4};
133ef3d217SAndrii Nakryiko 
143ef3d217SAndrii Nakryiko __naked __noinline __used
identity_subprog()153ef3d217SAndrii Nakryiko static unsigned long identity_subprog()
163ef3d217SAndrii Nakryiko {
173ef3d217SAndrii Nakryiko 	/* the simplest *static* 64-bit identity function */
183ef3d217SAndrii Nakryiko 	asm volatile (
193ef3d217SAndrii Nakryiko 		"r0 = r1;"
203ef3d217SAndrii Nakryiko 		"exit;"
213ef3d217SAndrii Nakryiko 	);
223ef3d217SAndrii Nakryiko }
233ef3d217SAndrii Nakryiko 
243ef3d217SAndrii Nakryiko __noinline __used
global_identity_subprog(__u64 x)253ef3d217SAndrii Nakryiko unsigned long global_identity_subprog(__u64 x)
263ef3d217SAndrii Nakryiko {
273ef3d217SAndrii Nakryiko 	/* the simplest *global* 64-bit identity function */
283ef3d217SAndrii Nakryiko 	return x;
293ef3d217SAndrii Nakryiko }
303ef3d217SAndrii Nakryiko 
313ef3d217SAndrii Nakryiko __naked __noinline __used
callback_subprog()323ef3d217SAndrii Nakryiko static unsigned long callback_subprog()
333ef3d217SAndrii Nakryiko {
343ef3d217SAndrii Nakryiko 	/* the simplest callback function */
353ef3d217SAndrii Nakryiko 	asm volatile (
363ef3d217SAndrii Nakryiko 		"r0 = 0;"
373ef3d217SAndrii Nakryiko 		"exit;"
383ef3d217SAndrii Nakryiko 	);
393ef3d217SAndrii Nakryiko }
403ef3d217SAndrii Nakryiko 
413ef3d217SAndrii Nakryiko SEC("?raw_tp")
423ef3d217SAndrii Nakryiko __success __log_level(2)
433ef3d217SAndrii Nakryiko __msg("7: (0f) r1 += r0")
443ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 6: (bf) r1 = r7")
453ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 5: (27) r0 *= 4")
463ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 11: (95) exit")
473ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs=r0 stack= before 10: (bf) r0 = r1")
483ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+5")
493ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6")
503ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
subprog_result_precise(void)513ef3d217SAndrii Nakryiko __naked int subprog_result_precise(void)
523ef3d217SAndrii Nakryiko {
533ef3d217SAndrii Nakryiko 	asm volatile (
543ef3d217SAndrii Nakryiko 		"r6 = 3;"
553ef3d217SAndrii Nakryiko 		/* pass r6 through r1 into subprog to get it back as r0;
563ef3d217SAndrii Nakryiko 		 * this whole chain will have to be marked as precise later
573ef3d217SAndrii Nakryiko 		 */
583ef3d217SAndrii Nakryiko 		"r1 = r6;"
593ef3d217SAndrii Nakryiko 		"call identity_subprog;"
603ef3d217SAndrii Nakryiko 		/* now use subprog's returned value (which is a
613ef3d217SAndrii Nakryiko 		 * r6 -> r1 -> r0 chain), as index into vals array, forcing
623ef3d217SAndrii Nakryiko 		 * all of that to be known precisely
633ef3d217SAndrii Nakryiko 		 */
643ef3d217SAndrii Nakryiko 		"r0 *= 4;"
653ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
663ef3d217SAndrii Nakryiko 		/* here r0->r1->r6 chain is forced to be precise and has to be
673ef3d217SAndrii Nakryiko 		 * propagated back to the beginning, including through the
683ef3d217SAndrii Nakryiko 		 * subprog call
693ef3d217SAndrii Nakryiko 		 */
703ef3d217SAndrii Nakryiko 		"r1 += r0;"
713ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
723ef3d217SAndrii Nakryiko 		"exit;"
733ef3d217SAndrii Nakryiko 		:
743ef3d217SAndrii Nakryiko 		: __imm_ptr(vals)
753ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
763ef3d217SAndrii Nakryiko 	);
773ef3d217SAndrii Nakryiko }
783ef3d217SAndrii Nakryiko 
793ef3d217SAndrii Nakryiko SEC("?raw_tp")
803ef3d217SAndrii Nakryiko __success __log_level(2)
813ef3d217SAndrii Nakryiko __msg("9: (0f) r1 += r0")
823ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 9 first_idx 0")
833ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 8: (bf) r1 = r7")
843ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 7: (27) r0 *= 4")
853ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 5: (a5) if r0 < 0x4 goto pc+1")
863ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r0 stack= before 4: (85) call pc+7")
global_subprog_result_precise(void)873ef3d217SAndrii Nakryiko __naked int global_subprog_result_precise(void)
883ef3d217SAndrii Nakryiko {
893ef3d217SAndrii Nakryiko 	asm volatile (
903ef3d217SAndrii Nakryiko 		"r6 = 3;"
913ef3d217SAndrii Nakryiko 		/* pass r6 through r1 into subprog to get it back as r0;
923ef3d217SAndrii Nakryiko 		 * given global_identity_subprog is global, precision won't
933ef3d217SAndrii Nakryiko 		 * propagate all the way back to r6
943ef3d217SAndrii Nakryiko 		 */
953ef3d217SAndrii Nakryiko 		"r1 = r6;"
963ef3d217SAndrii Nakryiko 		"call global_identity_subprog;"
973ef3d217SAndrii Nakryiko 		/* now use subprog's returned value (which is unknown now, so
983ef3d217SAndrii Nakryiko 		 * we need to clamp it), as index into vals array, forcing r0
993ef3d217SAndrii Nakryiko 		 * to be marked precise (with no effect on r6, though)
1003ef3d217SAndrii Nakryiko 		 */
1013ef3d217SAndrii Nakryiko 		"if r0 < %[vals_arr_sz] goto 1f;"
1023ef3d217SAndrii Nakryiko 		"r0 = %[vals_arr_sz] - 1;"
1033ef3d217SAndrii Nakryiko 	"1:"
1043ef3d217SAndrii Nakryiko 		"r0 *= 4;"
1053ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
1063ef3d217SAndrii Nakryiko 		/* here r0 is forced to be precise and has to be
1073ef3d217SAndrii Nakryiko 		 * propagated back to the global subprog call, but it
1083ef3d217SAndrii Nakryiko 		 * shouldn't go all the way to mark r6 as precise
1093ef3d217SAndrii Nakryiko 		 */
1103ef3d217SAndrii Nakryiko 		"r1 += r0;"
1113ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
1123ef3d217SAndrii Nakryiko 		"exit;"
1133ef3d217SAndrii Nakryiko 		:
1143ef3d217SAndrii Nakryiko 		: __imm_ptr(vals),
1153ef3d217SAndrii Nakryiko 		  __imm_const(vals_arr_sz, ARRAY_SIZE(vals))
1163ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
1173ef3d217SAndrii Nakryiko 	);
1183ef3d217SAndrii Nakryiko }
1193ef3d217SAndrii Nakryiko 
1203ef3d217SAndrii Nakryiko SEC("?raw_tp")
1213ef3d217SAndrii Nakryiko __success __log_level(2)
122*bfc5c19bSEduard Zingerman /* First simulated path does not include callback body,
123*bfc5c19bSEduard Zingerman  * r1 and r4 are always precise for bpf_loop() calls.
124*bfc5c19bSEduard Zingerman  */
125*bfc5c19bSEduard Zingerman __msg("9: (85) call bpf_loop#181")
126*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
127*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: parent state regs=r4 stack=:")
128*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9")
129*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r4 stack= before 8: (b7) r4 = 0")
130*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
131*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: parent state regs=r1 stack=:")
132*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9")
133*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1 stack= before 8: (b7) r4 = 0")
134*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1 stack= before 7: (b7) r3 = 0")
135*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1 stack= before 6: (bf) r2 = r8")
136*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1 stack= before 5: (bf) r1 = r6")
137*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3")
138*bfc5c19bSEduard Zingerman /* r6 precision propagation */
1393ef3d217SAndrii Nakryiko __msg("14: (0f) r1 += r6")
140b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 14 first_idx 9")
1413ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7")
1423ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4")
1433ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4")
1443ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0")
145b43550d7SEduard Zingerman __msg("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop")
146b43550d7SEduard Zingerman /* State entering callback body popped from states stack */
147b43550d7SEduard Zingerman __msg("from 9 to 17: frame1:")
148b43550d7SEduard Zingerman __msg("17: frame1: R1=scalar() R2=0 R10=fp0 cb")
149b43550d7SEduard Zingerman __msg("17: (b7) r0 = 0")
150b43550d7SEduard Zingerman __msg("18: (95) exit")
151b43550d7SEduard Zingerman __msg("returning from callee:")
152b43550d7SEduard Zingerman __msg("to caller at 9:")
153*bfc5c19bSEduard Zingerman __msg("frame 0: propagating r1,r4")
154b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
155*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1,r4 stack= before 18: (95) exit")
156b43550d7SEduard Zingerman __msg("from 18 to 9: safe")
callback_result_precise(void)1573ef3d217SAndrii Nakryiko __naked int callback_result_precise(void)
1583ef3d217SAndrii Nakryiko {
1593ef3d217SAndrii Nakryiko 	asm volatile (
1603ef3d217SAndrii Nakryiko 		"r6 = 3;"
1613ef3d217SAndrii Nakryiko 
1623ef3d217SAndrii Nakryiko 		/* call subprog and use result; r0 shouldn't propagate back to
1633ef3d217SAndrii Nakryiko 		 * callback_subprog
1643ef3d217SAndrii Nakryiko 		 */
1653ef3d217SAndrii Nakryiko 		"r1 = r6;"			/* nr_loops */
1663ef3d217SAndrii Nakryiko 		"r2 = %[callback_subprog];"	/* callback_fn */
1673ef3d217SAndrii Nakryiko 		"r3 = 0;"			/* callback_ctx */
1683ef3d217SAndrii Nakryiko 		"r4 = 0;"			/* flags */
1693ef3d217SAndrii Nakryiko 		"call %[bpf_loop];"
1703ef3d217SAndrii Nakryiko 
1713ef3d217SAndrii Nakryiko 		"r6 = r0;"
1723ef3d217SAndrii Nakryiko 		"if r6 > 3 goto 1f;"
1733ef3d217SAndrii Nakryiko 		"r6 *= 4;"
1743ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
1753ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
1763ef3d217SAndrii Nakryiko 		 * back to the bpf_loop() call, but not beyond
1773ef3d217SAndrii Nakryiko 		 */
1783ef3d217SAndrii Nakryiko 		"r1 += r6;"
1793ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
1803ef3d217SAndrii Nakryiko 	"1:"
1813ef3d217SAndrii Nakryiko 		"exit;"
1823ef3d217SAndrii Nakryiko 		:
1833ef3d217SAndrii Nakryiko 		: __imm_ptr(vals),
1843ef3d217SAndrii Nakryiko 		  __imm_ptr(callback_subprog),
1853ef3d217SAndrii Nakryiko 		  __imm(bpf_loop)
1863ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
1873ef3d217SAndrii Nakryiko 	);
1883ef3d217SAndrii Nakryiko }
1893ef3d217SAndrii Nakryiko 
1903ef3d217SAndrii Nakryiko SEC("?raw_tp")
1913ef3d217SAndrii Nakryiko __success __log_level(2)
1923ef3d217SAndrii Nakryiko __msg("7: (0f) r1 += r6")
1933ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 7 first_idx 0")
1943ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7")
1953ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4")
1963ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 11: (95) exit")
1973ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs= stack= before 10: (bf) r0 = r1")
1983ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs= stack= before 4: (85) call pc+5")
1993ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0")
2003ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_callee_saved_reg_precise(void)2013ef3d217SAndrii Nakryiko __naked int parent_callee_saved_reg_precise(void)
2023ef3d217SAndrii Nakryiko {
2033ef3d217SAndrii Nakryiko 	asm volatile (
2043ef3d217SAndrii Nakryiko 		"r6 = 3;"
2053ef3d217SAndrii Nakryiko 
2063ef3d217SAndrii Nakryiko 		/* call subprog and ignore result; we need this call only to
2073ef3d217SAndrii Nakryiko 		 * complicate jump history
2083ef3d217SAndrii Nakryiko 		 */
2093ef3d217SAndrii Nakryiko 		"r1 = 0;"
2103ef3d217SAndrii Nakryiko 		"call identity_subprog;"
2113ef3d217SAndrii Nakryiko 
2123ef3d217SAndrii Nakryiko 		"r6 *= 4;"
2133ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
2143ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
2153ef3d217SAndrii Nakryiko 		 * back to the beginning, handling (and ignoring) subprog call
2163ef3d217SAndrii Nakryiko 		 */
2173ef3d217SAndrii Nakryiko 		"r1 += r6;"
2183ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
2193ef3d217SAndrii Nakryiko 		"exit;"
2203ef3d217SAndrii Nakryiko 		:
2213ef3d217SAndrii Nakryiko 		: __imm_ptr(vals)
2223ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
2233ef3d217SAndrii Nakryiko 	);
2243ef3d217SAndrii Nakryiko }
2253ef3d217SAndrii Nakryiko 
2263ef3d217SAndrii Nakryiko SEC("?raw_tp")
2273ef3d217SAndrii Nakryiko __success __log_level(2)
2283ef3d217SAndrii Nakryiko __msg("7: (0f) r1 += r6")
2293ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 7 first_idx 0")
2303ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7")
2313ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4")
2323ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 4: (85) call pc+5")
2333ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0")
2343ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_callee_saved_reg_precise_global(void)2353ef3d217SAndrii Nakryiko __naked int parent_callee_saved_reg_precise_global(void)
2363ef3d217SAndrii Nakryiko {
2373ef3d217SAndrii Nakryiko 	asm volatile (
2383ef3d217SAndrii Nakryiko 		"r6 = 3;"
2393ef3d217SAndrii Nakryiko 
2403ef3d217SAndrii Nakryiko 		/* call subprog and ignore result; we need this call only to
2413ef3d217SAndrii Nakryiko 		 * complicate jump history
2423ef3d217SAndrii Nakryiko 		 */
2433ef3d217SAndrii Nakryiko 		"r1 = 0;"
2443ef3d217SAndrii Nakryiko 		"call global_identity_subprog;"
2453ef3d217SAndrii Nakryiko 
2463ef3d217SAndrii Nakryiko 		"r6 *= 4;"
2473ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
2483ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
2493ef3d217SAndrii Nakryiko 		 * back to the beginning, handling (and ignoring) subprog call
2503ef3d217SAndrii Nakryiko 		 */
2513ef3d217SAndrii Nakryiko 		"r1 += r6;"
2523ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
2533ef3d217SAndrii Nakryiko 		"exit;"
2543ef3d217SAndrii Nakryiko 		:
2553ef3d217SAndrii Nakryiko 		: __imm_ptr(vals)
2563ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
2573ef3d217SAndrii Nakryiko 	);
2583ef3d217SAndrii Nakryiko }
2593ef3d217SAndrii Nakryiko 
2603ef3d217SAndrii Nakryiko SEC("?raw_tp")
2613ef3d217SAndrii Nakryiko __success __log_level(2)
262b43550d7SEduard Zingerman /* First simulated path does not include callback body */
2633ef3d217SAndrii Nakryiko __msg("12: (0f) r1 += r6")
264b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 12 first_idx 9")
2653ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 11: (bf) r1 = r7")
2663ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 10: (27) r6 *= 4")
267b43550d7SEduard Zingerman __msg("mark_precise: frame0: regs=r6 stack= before 9: (85) call bpf_loop")
2683ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: parent state regs=r6 stack=:")
269b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9")
2703ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 8: (b7) r4 = 0")
2713ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 7: (b7) r3 = 0")
2723ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r2 = r8")
2733ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 5: (b7) r1 = 1")
2743ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3")
275b43550d7SEduard Zingerman /* State entering callback body popped from states stack */
276b43550d7SEduard Zingerman __msg("from 9 to 15: frame1:")
277b43550d7SEduard Zingerman __msg("15: frame1: R1=scalar() R2=0 R10=fp0 cb")
278b43550d7SEduard Zingerman __msg("15: (b7) r0 = 0")
279b43550d7SEduard Zingerman __msg("16: (95) exit")
280b43550d7SEduard Zingerman __msg("returning from callee:")
281b43550d7SEduard Zingerman __msg("to caller at 9:")
282*bfc5c19bSEduard Zingerman /* r1, r4 are always precise for bpf_loop(),
283b43550d7SEduard Zingerman  * r6 was marked before backtracking to callback body.
284b43550d7SEduard Zingerman  */
285*bfc5c19bSEduard Zingerman __msg("frame 0: propagating r1,r4,r6")
286b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
287*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1,r4,r6 stack= before 16: (95) exit")
288b43550d7SEduard Zingerman __msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0")
289b43550d7SEduard Zingerman __msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop")
290b43550d7SEduard Zingerman __msg("mark_precise: frame0: parent state regs= stack=:")
291b43550d7SEduard Zingerman __msg("from 16 to 9: safe")
parent_callee_saved_reg_precise_with_callback(void)2923ef3d217SAndrii Nakryiko __naked int parent_callee_saved_reg_precise_with_callback(void)
2933ef3d217SAndrii Nakryiko {
2943ef3d217SAndrii Nakryiko 	asm volatile (
2953ef3d217SAndrii Nakryiko 		"r6 = 3;"
2963ef3d217SAndrii Nakryiko 
2973ef3d217SAndrii Nakryiko 		/* call subprog and ignore result; we need this call only to
2983ef3d217SAndrii Nakryiko 		 * complicate jump history
2993ef3d217SAndrii Nakryiko 		 */
3003ef3d217SAndrii Nakryiko 		"r1 = 1;"			/* nr_loops */
3013ef3d217SAndrii Nakryiko 		"r2 = %[callback_subprog];"	/* callback_fn */
3023ef3d217SAndrii Nakryiko 		"r3 = 0;"			/* callback_ctx */
3033ef3d217SAndrii Nakryiko 		"r4 = 0;"			/* flags */
3043ef3d217SAndrii Nakryiko 		"call %[bpf_loop];"
3053ef3d217SAndrii Nakryiko 
3063ef3d217SAndrii Nakryiko 		"r6 *= 4;"
3073ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
3083ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
3093ef3d217SAndrii Nakryiko 		 * back to the beginning, handling (and ignoring) callback call
3103ef3d217SAndrii Nakryiko 		 */
3113ef3d217SAndrii Nakryiko 		"r1 += r6;"
3123ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
3133ef3d217SAndrii Nakryiko 		"exit;"
3143ef3d217SAndrii Nakryiko 		:
3153ef3d217SAndrii Nakryiko 		: __imm_ptr(vals),
3163ef3d217SAndrii Nakryiko 		  __imm_ptr(callback_subprog),
3173ef3d217SAndrii Nakryiko 		  __imm(bpf_loop)
3183ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
3193ef3d217SAndrii Nakryiko 	);
3203ef3d217SAndrii Nakryiko }
3213ef3d217SAndrii Nakryiko 
3223ef3d217SAndrii Nakryiko SEC("?raw_tp")
3233ef3d217SAndrii Nakryiko __success __log_level(2)
3243ef3d217SAndrii Nakryiko __msg("9: (0f) r1 += r6")
3253ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 9 first_idx 6")
3263ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7")
3273ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4")
3283ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)")
3293ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: parent state regs= stack=-8:")
3303ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 13 first_idx 0")
3313ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 13: (95) exit")
3323ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs= stack= before 12: (bf) r0 = r1")
3333ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs= stack= before 5: (85) call pc+6")
3343ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0")
3353ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6")
3363ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_stack_slot_precise(void)3373ef3d217SAndrii Nakryiko __naked int parent_stack_slot_precise(void)
3383ef3d217SAndrii Nakryiko {
3393ef3d217SAndrii Nakryiko 	asm volatile (
3403ef3d217SAndrii Nakryiko 		/* spill reg */
3413ef3d217SAndrii Nakryiko 		"r6 = 3;"
3423ef3d217SAndrii Nakryiko 		"*(u64 *)(r10 - 8) = r6;"
3433ef3d217SAndrii Nakryiko 
3443ef3d217SAndrii Nakryiko 		/* call subprog and ignore result; we need this call only to
3453ef3d217SAndrii Nakryiko 		 * complicate jump history
3463ef3d217SAndrii Nakryiko 		 */
3473ef3d217SAndrii Nakryiko 		"r1 = 0;"
3483ef3d217SAndrii Nakryiko 		"call identity_subprog;"
3493ef3d217SAndrii Nakryiko 
3503ef3d217SAndrii Nakryiko 		/* restore reg from stack; in this case we'll be carrying
3513ef3d217SAndrii Nakryiko 		 * stack mask when going back into subprog through jump
3523ef3d217SAndrii Nakryiko 		 * history
3533ef3d217SAndrii Nakryiko 		 */
3543ef3d217SAndrii Nakryiko 		"r6 = *(u64 *)(r10 - 8);"
3553ef3d217SAndrii Nakryiko 
3563ef3d217SAndrii Nakryiko 		"r6 *= 4;"
3573ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
3583ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
3593ef3d217SAndrii Nakryiko 		 * back to the beginning, handling (and ignoring) subprog call
3603ef3d217SAndrii Nakryiko 		 */
3613ef3d217SAndrii Nakryiko 		"r1 += r6;"
3623ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
3633ef3d217SAndrii Nakryiko 		"exit;"
3643ef3d217SAndrii Nakryiko 		:
3653ef3d217SAndrii Nakryiko 		: __imm_ptr(vals)
3663ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
3673ef3d217SAndrii Nakryiko 	);
3683ef3d217SAndrii Nakryiko }
3693ef3d217SAndrii Nakryiko 
3703ef3d217SAndrii Nakryiko SEC("?raw_tp")
3713ef3d217SAndrii Nakryiko __success __log_level(2)
3723ef3d217SAndrii Nakryiko __msg("9: (0f) r1 += r6")
3733ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 9 first_idx 6")
3743ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7")
3753ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4")
3763ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)")
3773ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: parent state regs= stack=-8:")
3783ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: last_idx 5 first_idx 0")
3793ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6")
3803ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0")
3813ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6")
3823ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_stack_slot_precise_global(void)3833ef3d217SAndrii Nakryiko __naked int parent_stack_slot_precise_global(void)
3843ef3d217SAndrii Nakryiko {
3853ef3d217SAndrii Nakryiko 	asm volatile (
3863ef3d217SAndrii Nakryiko 		/* spill reg */
3873ef3d217SAndrii Nakryiko 		"r6 = 3;"
3883ef3d217SAndrii Nakryiko 		"*(u64 *)(r10 - 8) = r6;"
3893ef3d217SAndrii Nakryiko 
3903ef3d217SAndrii Nakryiko 		/* call subprog and ignore result; we need this call only to
3913ef3d217SAndrii Nakryiko 		 * complicate jump history
3923ef3d217SAndrii Nakryiko 		 */
3933ef3d217SAndrii Nakryiko 		"r1 = 0;"
3943ef3d217SAndrii Nakryiko 		"call global_identity_subprog;"
3953ef3d217SAndrii Nakryiko 
3963ef3d217SAndrii Nakryiko 		/* restore reg from stack; in this case we'll be carrying
3973ef3d217SAndrii Nakryiko 		 * stack mask when going back into subprog through jump
3983ef3d217SAndrii Nakryiko 		 * history
3993ef3d217SAndrii Nakryiko 		 */
4003ef3d217SAndrii Nakryiko 		"r6 = *(u64 *)(r10 - 8);"
4013ef3d217SAndrii Nakryiko 
4023ef3d217SAndrii Nakryiko 		"r6 *= 4;"
4033ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
4043ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
4053ef3d217SAndrii Nakryiko 		 * back to the beginning, handling (and ignoring) subprog call
4063ef3d217SAndrii Nakryiko 		 */
4073ef3d217SAndrii Nakryiko 		"r1 += r6;"
4083ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
4093ef3d217SAndrii Nakryiko 		"exit;"
4103ef3d217SAndrii Nakryiko 		:
4113ef3d217SAndrii Nakryiko 		: __imm_ptr(vals)
4123ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
4133ef3d217SAndrii Nakryiko 	);
4143ef3d217SAndrii Nakryiko }
4153ef3d217SAndrii Nakryiko 
4163ef3d217SAndrii Nakryiko SEC("?raw_tp")
4173ef3d217SAndrii Nakryiko __success __log_level(2)
418b43550d7SEduard Zingerman /* First simulated path does not include callback body */
4193ef3d217SAndrii Nakryiko __msg("14: (0f) r1 += r6")
420b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 14 first_idx 10")
4213ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7")
4223ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4")
4233ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 11: (79) r6 = *(u64 *)(r10 -8)")
424b43550d7SEduard Zingerman __msg("mark_precise: frame0: regs= stack=-8 before 10: (85) call bpf_loop")
4253ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: parent state regs= stack=-8:")
426b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 9 first_idx 0 subseq_idx 10")
4273ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 9: (b7) r4 = 0")
4283ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 8: (b7) r3 = 0")
4293ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r2 = r8")
4303ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 6: (bf) r1 = r6")
4313ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -8) = r6")
4323ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3")
433b43550d7SEduard Zingerman /* State entering callback body popped from states stack */
434b43550d7SEduard Zingerman __msg("from 10 to 17: frame1:")
435b43550d7SEduard Zingerman __msg("17: frame1: R1=scalar() R2=0 R10=fp0 cb")
436b43550d7SEduard Zingerman __msg("17: (b7) r0 = 0")
437b43550d7SEduard Zingerman __msg("18: (95) exit")
438b43550d7SEduard Zingerman __msg("returning from callee:")
439b43550d7SEduard Zingerman __msg("to caller at 10:")
440*bfc5c19bSEduard Zingerman /* r1, r4 are always precise for bpf_loop(),
441b43550d7SEduard Zingerman  * fp-8 was marked before backtracking to callback body.
442b43550d7SEduard Zingerman  */
443*bfc5c19bSEduard Zingerman __msg("frame 0: propagating r1,r4,fp-8")
444b43550d7SEduard Zingerman __msg("mark_precise: frame0: last_idx 10 first_idx 10 subseq_idx -1")
445*bfc5c19bSEduard Zingerman __msg("mark_precise: frame0: regs=r1,r4 stack=-8 before 18: (95) exit")
446b43550d7SEduard Zingerman __msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0")
447b43550d7SEduard Zingerman __msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181")
448b43550d7SEduard Zingerman __msg("mark_precise: frame0: parent state regs= stack=:")
449b43550d7SEduard Zingerman __msg("from 18 to 10: safe")
parent_stack_slot_precise_with_callback(void)4503ef3d217SAndrii Nakryiko __naked int parent_stack_slot_precise_with_callback(void)
4513ef3d217SAndrii Nakryiko {
4523ef3d217SAndrii Nakryiko 	asm volatile (
4533ef3d217SAndrii Nakryiko 		/* spill reg */
4543ef3d217SAndrii Nakryiko 		"r6 = 3;"
4553ef3d217SAndrii Nakryiko 		"*(u64 *)(r10 - 8) = r6;"
4563ef3d217SAndrii Nakryiko 
4573ef3d217SAndrii Nakryiko 		/* ensure we have callback frame in jump history */
4583ef3d217SAndrii Nakryiko 		"r1 = r6;"			/* nr_loops */
4593ef3d217SAndrii Nakryiko 		"r2 = %[callback_subprog];"	/* callback_fn */
4603ef3d217SAndrii Nakryiko 		"r3 = 0;"			/* callback_ctx */
4613ef3d217SAndrii Nakryiko 		"r4 = 0;"			/* flags */
4623ef3d217SAndrii Nakryiko 		"call %[bpf_loop];"
4633ef3d217SAndrii Nakryiko 
4643ef3d217SAndrii Nakryiko 		/* restore reg from stack; in this case we'll be carrying
4653ef3d217SAndrii Nakryiko 		 * stack mask when going back into subprog through jump
4663ef3d217SAndrii Nakryiko 		 * history
4673ef3d217SAndrii Nakryiko 		 */
4683ef3d217SAndrii Nakryiko 		"r6 = *(u64 *)(r10 - 8);"
4693ef3d217SAndrii Nakryiko 
4703ef3d217SAndrii Nakryiko 		"r6 *= 4;"
4713ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
4723ef3d217SAndrii Nakryiko 		/* here r6 is forced to be precise and has to be propagated
4733ef3d217SAndrii Nakryiko 		 * back to the beginning, handling (and ignoring) subprog call
4743ef3d217SAndrii Nakryiko 		 */
4753ef3d217SAndrii Nakryiko 		"r1 += r6;"
4763ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
4773ef3d217SAndrii Nakryiko 		"exit;"
4783ef3d217SAndrii Nakryiko 		:
4793ef3d217SAndrii Nakryiko 		: __imm_ptr(vals),
4803ef3d217SAndrii Nakryiko 		  __imm_ptr(callback_subprog),
4813ef3d217SAndrii Nakryiko 		  __imm(bpf_loop)
4823ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
4833ef3d217SAndrii Nakryiko 	);
4843ef3d217SAndrii Nakryiko }
4853ef3d217SAndrii Nakryiko 
4863ef3d217SAndrii Nakryiko __noinline __used
subprog_with_precise_arg(__u64 x)4873ef3d217SAndrii Nakryiko static __u64 subprog_with_precise_arg(__u64 x)
4883ef3d217SAndrii Nakryiko {
4893ef3d217SAndrii Nakryiko 	return vals[x]; /* x is forced to be precise */
4903ef3d217SAndrii Nakryiko }
4913ef3d217SAndrii Nakryiko 
4923ef3d217SAndrii Nakryiko SEC("?raw_tp")
4933ef3d217SAndrii Nakryiko __success __log_level(2)
4943ef3d217SAndrii Nakryiko __msg("8: (0f) r2 += r1")
4953ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: last_idx 8 first_idx 0")
4963ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs=r1 stack= before 6: (18) r2 = ")
4973ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs=r1 stack= before 5: (67) r1 <<= 2")
4983ef3d217SAndrii Nakryiko __msg("mark_precise: frame1: regs=r1 stack= before 2: (85) call pc+2")
4993ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r1 stack= before 1: (bf) r1 = r6")
5003ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: regs=r6 stack= before 0: (b7) r6 = 3")
subprog_arg_precise(void)5013ef3d217SAndrii Nakryiko __naked int subprog_arg_precise(void)
5023ef3d217SAndrii Nakryiko {
5033ef3d217SAndrii Nakryiko 	asm volatile (
5043ef3d217SAndrii Nakryiko 		"r6 = 3;"
5053ef3d217SAndrii Nakryiko 		"r1 = r6;"
5063ef3d217SAndrii Nakryiko 		/* subprog_with_precise_arg expects its argument to be
5073ef3d217SAndrii Nakryiko 		 * precise, so r1->r6 will be marked precise from inside the
5083ef3d217SAndrii Nakryiko 		 * subprog
5093ef3d217SAndrii Nakryiko 		 */
5103ef3d217SAndrii Nakryiko 		"call subprog_with_precise_arg;"
5113ef3d217SAndrii Nakryiko 		"r0 += r6;"
5123ef3d217SAndrii Nakryiko 		"exit;"
5133ef3d217SAndrii Nakryiko 		:
5143ef3d217SAndrii Nakryiko 		:
5153ef3d217SAndrii Nakryiko 		: __clobber_common, "r6"
5163ef3d217SAndrii Nakryiko 	);
5173ef3d217SAndrii Nakryiko }
5183ef3d217SAndrii Nakryiko 
5193ef3d217SAndrii Nakryiko /* r1 is pointer to stack slot;
5203ef3d217SAndrii Nakryiko  * r2 is a register to spill into that slot
5213ef3d217SAndrii Nakryiko  * subprog also spills r2 into its own stack slot
5223ef3d217SAndrii Nakryiko  */
5233ef3d217SAndrii Nakryiko __naked __noinline __used
subprog_spill_reg_precise(void)5243ef3d217SAndrii Nakryiko static __u64 subprog_spill_reg_precise(void)
5253ef3d217SAndrii Nakryiko {
5263ef3d217SAndrii Nakryiko 	asm volatile (
5273ef3d217SAndrii Nakryiko 		/* spill to parent stack */
5283ef3d217SAndrii Nakryiko 		"*(u64 *)(r1 + 0) = r2;"
5293ef3d217SAndrii Nakryiko 		/* spill to subprog stack (we use -16 offset to avoid
5303ef3d217SAndrii Nakryiko 		 * accidental confusion with parent's -8 stack slot in
5313ef3d217SAndrii Nakryiko 		 * verifier log output)
5323ef3d217SAndrii Nakryiko 		 */
5333ef3d217SAndrii Nakryiko 		"*(u64 *)(r10 - 16) = r2;"
5343ef3d217SAndrii Nakryiko 		/* use both spills as return result to propagete precision everywhere */
5353ef3d217SAndrii Nakryiko 		"r0 = *(u64 *)(r10 - 16);"
5363ef3d217SAndrii Nakryiko 		"r2 = *(u64 *)(r1 + 0);"
5373ef3d217SAndrii Nakryiko 		"r0 += r2;"
5383ef3d217SAndrii Nakryiko 		"exit;"
5393ef3d217SAndrii Nakryiko 	);
5403ef3d217SAndrii Nakryiko }
5413ef3d217SAndrii Nakryiko 
5423ef3d217SAndrii Nakryiko SEC("?raw_tp")
5433ef3d217SAndrii Nakryiko __success __log_level(2)
5443ef3d217SAndrii Nakryiko /* precision backtracking can't currently handle stack access not through r10,
5453ef3d217SAndrii Nakryiko  * so we won't be able to mark stack slot fp-8 as precise, and so will
5463ef3d217SAndrii Nakryiko  * fallback to forcing all as precise
5473ef3d217SAndrii Nakryiko  */
5483ef3d217SAndrii Nakryiko __msg("mark_precise: frame0: falling back to forcing all scalars precise")
subprog_spill_into_parent_stack_slot_precise(void)5493ef3d217SAndrii Nakryiko __naked int subprog_spill_into_parent_stack_slot_precise(void)
5503ef3d217SAndrii Nakryiko {
5513ef3d217SAndrii Nakryiko 	asm volatile (
5523ef3d217SAndrii Nakryiko 		"r6 = 1;"
5533ef3d217SAndrii Nakryiko 
5543ef3d217SAndrii Nakryiko 		/* pass pointer to stack slot and r6 to subprog;
5553ef3d217SAndrii Nakryiko 		 * r6 will be marked precise and spilled into fp-8 slot, which
5563ef3d217SAndrii Nakryiko 		 * also should be marked precise
5573ef3d217SAndrii Nakryiko 		 */
5583ef3d217SAndrii Nakryiko 		"r1 = r10;"
5593ef3d217SAndrii Nakryiko 		"r1 += -8;"
5603ef3d217SAndrii Nakryiko 		"r2 = r6;"
5613ef3d217SAndrii Nakryiko 		"call subprog_spill_reg_precise;"
5623ef3d217SAndrii Nakryiko 
5633ef3d217SAndrii Nakryiko 		/* restore reg from stack; in this case we'll be carrying
5643ef3d217SAndrii Nakryiko 		 * stack mask when going back into subprog through jump
5653ef3d217SAndrii Nakryiko 		 * history
5663ef3d217SAndrii Nakryiko 		 */
5673ef3d217SAndrii Nakryiko 		"r7 = *(u64 *)(r10 - 8);"
5683ef3d217SAndrii Nakryiko 
5693ef3d217SAndrii Nakryiko 		"r7 *= 4;"
5703ef3d217SAndrii Nakryiko 		"r1 = %[vals];"
5713ef3d217SAndrii Nakryiko 		/* here r7 is forced to be precise and has to be propagated
5723ef3d217SAndrii Nakryiko 		 * back to the beginning, handling subprog call and logic
5733ef3d217SAndrii Nakryiko 		 */
5743ef3d217SAndrii Nakryiko 		"r1 += r7;"
5753ef3d217SAndrii Nakryiko 		"r0 = *(u32 *)(r1 + 0);"
5763ef3d217SAndrii Nakryiko 		"exit;"
5773ef3d217SAndrii Nakryiko 		:
5783ef3d217SAndrii Nakryiko 		: __imm_ptr(vals)
5793ef3d217SAndrii Nakryiko 		: __clobber_common, "r6", "r7"
5803ef3d217SAndrii Nakryiko 	);
5813ef3d217SAndrii Nakryiko }
5823ef3d217SAndrii Nakryiko 
5833ef3d217SAndrii Nakryiko __naked __noinline __used
subprog_with_checkpoint(void)5843ef3d217SAndrii Nakryiko static __u64 subprog_with_checkpoint(void)
5853ef3d217SAndrii Nakryiko {
5863ef3d217SAndrii Nakryiko 	asm volatile (
5873ef3d217SAndrii Nakryiko 		"r0 = 0;"
5883ef3d217SAndrii Nakryiko 		/* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */
5893ef3d217SAndrii Nakryiko 		"goto +0;"
5903ef3d217SAndrii Nakryiko 		"exit;"
5913ef3d217SAndrii Nakryiko 	);
5923ef3d217SAndrii Nakryiko }
5933ef3d217SAndrii Nakryiko 
5943ef3d217SAndrii Nakryiko char _license[] SEC("license") = "GPL";
595