157400dccSAndrii Nakryiko // SPDX-License-Identifier: GPL-2.0
257400dccSAndrii Nakryiko /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
357400dccSAndrii Nakryiko 
457400dccSAndrii Nakryiko #include <stdbool.h>
557400dccSAndrii Nakryiko #include <linux/bpf.h>
657400dccSAndrii Nakryiko #include <bpf/bpf_helpers.h>
757400dccSAndrii Nakryiko #include "bpf_misc.h"
857400dccSAndrii Nakryiko 
957400dccSAndrii Nakryiko #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
1057400dccSAndrii Nakryiko 
1157400dccSAndrii Nakryiko static volatile int zero = 0;
1257400dccSAndrii Nakryiko 
1357400dccSAndrii Nakryiko int my_pid;
1457400dccSAndrii Nakryiko int arr[256];
1557400dccSAndrii Nakryiko int small_arr[16] SEC(".data.small_arr");
1657400dccSAndrii Nakryiko 
177f764ea0SEduard Zingerman struct {
187f764ea0SEduard Zingerman 	__uint(type, BPF_MAP_TYPE_HASH);
197f764ea0SEduard Zingerman 	__uint(max_entries, 10);
207f764ea0SEduard Zingerman 	__type(key, int);
217f764ea0SEduard Zingerman 	__type(value, int);
227f764ea0SEduard Zingerman } amap SEC(".maps");
237f764ea0SEduard Zingerman 
2457400dccSAndrii Nakryiko #ifdef REAL_TEST
2557400dccSAndrii Nakryiko #define MY_PID_GUARD() if (my_pid != (bpf_get_current_pid_tgid() >> 32)) return 0
2657400dccSAndrii Nakryiko #else
2757400dccSAndrii Nakryiko #define MY_PID_GUARD() ({ })
2857400dccSAndrii Nakryiko #endif
2957400dccSAndrii Nakryiko 
3057400dccSAndrii Nakryiko SEC("?raw_tp")
3157400dccSAndrii Nakryiko __failure __msg("math between map_value pointer and register with unbounded min value is not allowed")
iter_err_unsafe_c_loop(const void * ctx)3257400dccSAndrii Nakryiko int iter_err_unsafe_c_loop(const void *ctx)
3357400dccSAndrii Nakryiko {
3457400dccSAndrii Nakryiko 	struct bpf_iter_num it;
3557400dccSAndrii Nakryiko 	int *v, i = zero; /* obscure initial value of i */
3657400dccSAndrii Nakryiko 
3757400dccSAndrii Nakryiko 	MY_PID_GUARD();
3857400dccSAndrii Nakryiko 
3957400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 1000);
4057400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
4157400dccSAndrii Nakryiko 		i++;
4257400dccSAndrii Nakryiko 	}
4357400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
4457400dccSAndrii Nakryiko 
4557400dccSAndrii Nakryiko 	small_arr[i] = 123; /* invalid */
4657400dccSAndrii Nakryiko 
4757400dccSAndrii Nakryiko 	return 0;
4857400dccSAndrii Nakryiko }
4957400dccSAndrii Nakryiko 
5057400dccSAndrii Nakryiko SEC("?raw_tp")
5157400dccSAndrii Nakryiko __failure __msg("unbounded memory access")
iter_err_unsafe_asm_loop(const void * ctx)5257400dccSAndrii Nakryiko int iter_err_unsafe_asm_loop(const void *ctx)
5357400dccSAndrii Nakryiko {
5457400dccSAndrii Nakryiko 	struct bpf_iter_num it;
5557400dccSAndrii Nakryiko 
5657400dccSAndrii Nakryiko 	MY_PID_GUARD();
5757400dccSAndrii Nakryiko 
5857400dccSAndrii Nakryiko 	asm volatile (
5957400dccSAndrii Nakryiko 		"r6 = %[zero];" /* iteration counter */
6057400dccSAndrii Nakryiko 		"r1 = %[it];" /* iterator state */
6157400dccSAndrii Nakryiko 		"r2 = 0;"
6257400dccSAndrii Nakryiko 		"r3 = 1000;"
6357400dccSAndrii Nakryiko 		"r4 = 1;"
6457400dccSAndrii Nakryiko 		"call %[bpf_iter_num_new];"
6557400dccSAndrii Nakryiko 	"loop:"
6657400dccSAndrii Nakryiko 		"r1 = %[it];"
6757400dccSAndrii Nakryiko 		"call %[bpf_iter_num_next];"
6857400dccSAndrii Nakryiko 		"if r0 == 0 goto out;"
6957400dccSAndrii Nakryiko 		"r6 += 1;"
7057400dccSAndrii Nakryiko 		"goto loop;"
7157400dccSAndrii Nakryiko 	"out:"
7257400dccSAndrii Nakryiko 		"r1 = %[it];"
7357400dccSAndrii Nakryiko 		"call %[bpf_iter_num_destroy];"
7457400dccSAndrii Nakryiko 		"r1 = %[small_arr];"
7557400dccSAndrii Nakryiko 		"r2 = r6;"
7657400dccSAndrii Nakryiko 		"r2 <<= 2;"
7757400dccSAndrii Nakryiko 		"r1 += r2;"
7857400dccSAndrii Nakryiko 		"*(u32 *)(r1 + 0) = r6;" /* invalid */
7957400dccSAndrii Nakryiko 		:
8057400dccSAndrii Nakryiko 		: [it]"r"(&it),
8157400dccSAndrii Nakryiko 		  [small_arr]"p"(small_arr),
8257400dccSAndrii Nakryiko 		  [zero]"p"(zero),
8357400dccSAndrii Nakryiko 		  __imm(bpf_iter_num_new),
8457400dccSAndrii Nakryiko 		  __imm(bpf_iter_num_next),
8557400dccSAndrii Nakryiko 		  __imm(bpf_iter_num_destroy)
8657400dccSAndrii Nakryiko 		: __clobber_common, "r6"
8757400dccSAndrii Nakryiko 	);
8857400dccSAndrii Nakryiko 
8957400dccSAndrii Nakryiko 	return 0;
9057400dccSAndrii Nakryiko }
9157400dccSAndrii Nakryiko 
9257400dccSAndrii Nakryiko SEC("raw_tp")
9357400dccSAndrii Nakryiko __success
iter_while_loop(const void * ctx)9457400dccSAndrii Nakryiko int iter_while_loop(const void *ctx)
9557400dccSAndrii Nakryiko {
9657400dccSAndrii Nakryiko 	struct bpf_iter_num it;
97c8ed6685SAndrii Nakryiko 	int *v;
9857400dccSAndrii Nakryiko 
9957400dccSAndrii Nakryiko 	MY_PID_GUARD();
10057400dccSAndrii Nakryiko 
10157400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 3);
10257400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
10357400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
10457400dccSAndrii Nakryiko 	}
10557400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
10657400dccSAndrii Nakryiko 
10757400dccSAndrii Nakryiko 	return 0;
10857400dccSAndrii Nakryiko }
10957400dccSAndrii Nakryiko 
11057400dccSAndrii Nakryiko SEC("raw_tp")
11157400dccSAndrii Nakryiko __success
iter_while_loop_auto_cleanup(const void * ctx)11257400dccSAndrii Nakryiko int iter_while_loop_auto_cleanup(const void *ctx)
11357400dccSAndrii Nakryiko {
11457400dccSAndrii Nakryiko 	__attribute__((cleanup(bpf_iter_num_destroy))) struct bpf_iter_num it;
115c8ed6685SAndrii Nakryiko 	int *v;
11657400dccSAndrii Nakryiko 
11757400dccSAndrii Nakryiko 	MY_PID_GUARD();
11857400dccSAndrii Nakryiko 
11957400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 3);
12057400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
12157400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
12257400dccSAndrii Nakryiko 	}
12357400dccSAndrii Nakryiko 	/* (!) no explicit bpf_iter_num_destroy() */
12457400dccSAndrii Nakryiko 
12557400dccSAndrii Nakryiko 	return 0;
12657400dccSAndrii Nakryiko }
12757400dccSAndrii Nakryiko 
12857400dccSAndrii Nakryiko SEC("raw_tp")
12957400dccSAndrii Nakryiko __success
iter_for_loop(const void * ctx)13057400dccSAndrii Nakryiko int iter_for_loop(const void *ctx)
13157400dccSAndrii Nakryiko {
13257400dccSAndrii Nakryiko 	struct bpf_iter_num it;
133c8ed6685SAndrii Nakryiko 	int *v;
13457400dccSAndrii Nakryiko 
13557400dccSAndrii Nakryiko 	MY_PID_GUARD();
13657400dccSAndrii Nakryiko 
13757400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 5, 10);
13857400dccSAndrii Nakryiko 	for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) {
13957400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
14057400dccSAndrii Nakryiko 	}
14157400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
14257400dccSAndrii Nakryiko 
14357400dccSAndrii Nakryiko 	return 0;
14457400dccSAndrii Nakryiko }
14557400dccSAndrii Nakryiko 
14657400dccSAndrii Nakryiko SEC("raw_tp")
14757400dccSAndrii Nakryiko __success
iter_bpf_for_each_macro(const void * ctx)14857400dccSAndrii Nakryiko int iter_bpf_for_each_macro(const void *ctx)
14957400dccSAndrii Nakryiko {
15057400dccSAndrii Nakryiko 	int *v;
15157400dccSAndrii Nakryiko 
15257400dccSAndrii Nakryiko 	MY_PID_GUARD();
15357400dccSAndrii Nakryiko 
15457400dccSAndrii Nakryiko 	bpf_for_each(num, v, 5, 10) {
15557400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
15657400dccSAndrii Nakryiko 	}
15757400dccSAndrii Nakryiko 
15857400dccSAndrii Nakryiko 	return 0;
15957400dccSAndrii Nakryiko }
16057400dccSAndrii Nakryiko 
16157400dccSAndrii Nakryiko SEC("raw_tp")
16257400dccSAndrii Nakryiko __success
iter_bpf_for_macro(const void * ctx)16357400dccSAndrii Nakryiko int iter_bpf_for_macro(const void *ctx)
16457400dccSAndrii Nakryiko {
16557400dccSAndrii Nakryiko 	int i;
16657400dccSAndrii Nakryiko 
16757400dccSAndrii Nakryiko 	MY_PID_GUARD();
16857400dccSAndrii Nakryiko 
16957400dccSAndrii Nakryiko 	bpf_for(i, 5, 10) {
17057400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E2 VAL: v=%d", i);
17157400dccSAndrii Nakryiko 	}
17257400dccSAndrii Nakryiko 
17357400dccSAndrii Nakryiko 	return 0;
17457400dccSAndrii Nakryiko }
17557400dccSAndrii Nakryiko 
17657400dccSAndrii Nakryiko SEC("raw_tp")
17757400dccSAndrii Nakryiko __success
iter_pragma_unroll_loop(const void * ctx)17857400dccSAndrii Nakryiko int iter_pragma_unroll_loop(const void *ctx)
17957400dccSAndrii Nakryiko {
18057400dccSAndrii Nakryiko 	struct bpf_iter_num it;
18157400dccSAndrii Nakryiko 	int *v, i;
18257400dccSAndrii Nakryiko 
18357400dccSAndrii Nakryiko 	MY_PID_GUARD();
18457400dccSAndrii Nakryiko 
18557400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 2);
18657400dccSAndrii Nakryiko #pragma nounroll
18757400dccSAndrii Nakryiko 	for (i = 0; i < 3; i++) {
18857400dccSAndrii Nakryiko 		v = bpf_iter_num_next(&it);
18957400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
19057400dccSAndrii Nakryiko 	}
19157400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
19257400dccSAndrii Nakryiko 
19357400dccSAndrii Nakryiko 	return 0;
19457400dccSAndrii Nakryiko }
19557400dccSAndrii Nakryiko 
19657400dccSAndrii Nakryiko SEC("raw_tp")
19757400dccSAndrii Nakryiko __success
iter_manual_unroll_loop(const void * ctx)19857400dccSAndrii Nakryiko int iter_manual_unroll_loop(const void *ctx)
19957400dccSAndrii Nakryiko {
20057400dccSAndrii Nakryiko 	struct bpf_iter_num it;
201c8ed6685SAndrii Nakryiko 	int *v;
20257400dccSAndrii Nakryiko 
20357400dccSAndrii Nakryiko 	MY_PID_GUARD();
20457400dccSAndrii Nakryiko 
20557400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 100, 200);
20657400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
20757400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
20857400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
20957400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
21057400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
21157400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
21257400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
21357400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1);
21457400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
21557400dccSAndrii Nakryiko 
21657400dccSAndrii Nakryiko 	return 0;
21757400dccSAndrii Nakryiko }
21857400dccSAndrii Nakryiko 
21957400dccSAndrii Nakryiko SEC("raw_tp")
22057400dccSAndrii Nakryiko __success
iter_multiple_sequential_loops(const void * ctx)22157400dccSAndrii Nakryiko int iter_multiple_sequential_loops(const void *ctx)
22257400dccSAndrii Nakryiko {
22357400dccSAndrii Nakryiko 	struct bpf_iter_num it;
22457400dccSAndrii Nakryiko 	int *v, i;
22557400dccSAndrii Nakryiko 
22657400dccSAndrii Nakryiko 	MY_PID_GUARD();
22757400dccSAndrii Nakryiko 
22857400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 3);
22957400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
23057400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E1 VAL: v=%d", *v);
23157400dccSAndrii Nakryiko 	}
23257400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
23357400dccSAndrii Nakryiko 
23457400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 5, 10);
23557400dccSAndrii Nakryiko 	for (v = bpf_iter_num_next(&it); v; v = bpf_iter_num_next(&it)) {
23657400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E2 VAL: v=%d", *v);
23757400dccSAndrii Nakryiko 	}
23857400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
23957400dccSAndrii Nakryiko 
24057400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 2);
24157400dccSAndrii Nakryiko #pragma nounroll
24257400dccSAndrii Nakryiko 	for (i = 0; i < 3; i++) {
24357400dccSAndrii Nakryiko 		v = bpf_iter_num_next(&it);
24457400dccSAndrii Nakryiko 		bpf_printk("ITER_BASIC: E3 VAL: i=%d v=%d", i, v ? *v : -1);
24557400dccSAndrii Nakryiko 	}
24657400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
24757400dccSAndrii Nakryiko 
24857400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 100, 200);
24957400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
25057400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
25157400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
25257400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
25357400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
25457400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d", v ? *v : -1);
25557400dccSAndrii Nakryiko 	v = bpf_iter_num_next(&it);
25657400dccSAndrii Nakryiko 	bpf_printk("ITER_BASIC: E4 VAL: v=%d\n", v ? *v : -1);
25757400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
25857400dccSAndrii Nakryiko 
25957400dccSAndrii Nakryiko 	return 0;
26057400dccSAndrii Nakryiko }
26157400dccSAndrii Nakryiko 
26257400dccSAndrii Nakryiko SEC("raw_tp")
26357400dccSAndrii Nakryiko __success
iter_limit_cond_break_loop(const void * ctx)26457400dccSAndrii Nakryiko int iter_limit_cond_break_loop(const void *ctx)
26557400dccSAndrii Nakryiko {
26657400dccSAndrii Nakryiko 	struct bpf_iter_num it;
26757400dccSAndrii Nakryiko 	int *v, i = 0, sum = 0;
26857400dccSAndrii Nakryiko 
26957400dccSAndrii Nakryiko 	MY_PID_GUARD();
27057400dccSAndrii Nakryiko 
27157400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 10);
27257400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
27357400dccSAndrii Nakryiko 		bpf_printk("ITER_SIMPLE: i=%d v=%d", i, *v);
27457400dccSAndrii Nakryiko 		sum += *v;
27557400dccSAndrii Nakryiko 
27657400dccSAndrii Nakryiko 		i++;
27757400dccSAndrii Nakryiko 		if (i > 3)
27857400dccSAndrii Nakryiko 			break;
27957400dccSAndrii Nakryiko 	}
28057400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
28157400dccSAndrii Nakryiko 
28257400dccSAndrii Nakryiko 	bpf_printk("ITER_SIMPLE: sum=%d\n", sum);
28357400dccSAndrii Nakryiko 
28457400dccSAndrii Nakryiko 	return 0;
28557400dccSAndrii Nakryiko }
28657400dccSAndrii Nakryiko 
28757400dccSAndrii Nakryiko SEC("raw_tp")
28857400dccSAndrii Nakryiko __success
iter_obfuscate_counter(const void * ctx)28957400dccSAndrii Nakryiko int iter_obfuscate_counter(const void *ctx)
29057400dccSAndrii Nakryiko {
29157400dccSAndrii Nakryiko 	struct bpf_iter_num it;
29257400dccSAndrii Nakryiko 	int *v, sum = 0;
29357400dccSAndrii Nakryiko 	/* Make i's initial value unknowable for verifier to prevent it from
29457400dccSAndrii Nakryiko 	 * pruning if/else branch inside the loop body and marking i as precise.
29557400dccSAndrii Nakryiko 	 */
29657400dccSAndrii Nakryiko 	int i = zero;
29757400dccSAndrii Nakryiko 
29857400dccSAndrii Nakryiko 	MY_PID_GUARD();
29957400dccSAndrii Nakryiko 
30057400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 10);
30157400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
30257400dccSAndrii Nakryiko 		int x;
30357400dccSAndrii Nakryiko 
30457400dccSAndrii Nakryiko 		i += 1;
30557400dccSAndrii Nakryiko 
30657400dccSAndrii Nakryiko 		/* If we initialized i as `int i = 0;` above, verifier would
30757400dccSAndrii Nakryiko 		 * track that i becomes 1 on first iteration after increment
30857400dccSAndrii Nakryiko 		 * above, and here verifier would eagerly prune else branch
30957400dccSAndrii Nakryiko 		 * and mark i as precise, ruining open-coded iterator logic
31057400dccSAndrii Nakryiko 		 * completely, as each next iteration would have a different
31157400dccSAndrii Nakryiko 		 * *precise* value of i, and thus there would be no
31257400dccSAndrii Nakryiko 		 * convergence of state. This would result in reaching maximum
31357400dccSAndrii Nakryiko 		 * instruction limit, no matter what the limit is.
31457400dccSAndrii Nakryiko 		 */
31557400dccSAndrii Nakryiko 		if (i == 1)
31657400dccSAndrii Nakryiko 			x = 123;
31757400dccSAndrii Nakryiko 		else
31857400dccSAndrii Nakryiko 			x = i * 3 + 1;
31957400dccSAndrii Nakryiko 
32057400dccSAndrii Nakryiko 		bpf_printk("ITER_OBFUSCATE_COUNTER: i=%d v=%d x=%d", i, *v, x);
32157400dccSAndrii Nakryiko 
32257400dccSAndrii Nakryiko 		sum += x;
32357400dccSAndrii Nakryiko 	}
32457400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
32557400dccSAndrii Nakryiko 
32657400dccSAndrii Nakryiko 	bpf_printk("ITER_OBFUSCATE_COUNTER: sum=%d\n", sum);
32757400dccSAndrii Nakryiko 
32857400dccSAndrii Nakryiko 	return 0;
32957400dccSAndrii Nakryiko }
33057400dccSAndrii Nakryiko 
33157400dccSAndrii Nakryiko SEC("raw_tp")
33257400dccSAndrii Nakryiko __success
iter_search_loop(const void * ctx)33357400dccSAndrii Nakryiko int iter_search_loop(const void *ctx)
33457400dccSAndrii Nakryiko {
33557400dccSAndrii Nakryiko 	struct bpf_iter_num it;
33657400dccSAndrii Nakryiko 	int *v, *elem = NULL;
33757400dccSAndrii Nakryiko 	bool found = false;
33857400dccSAndrii Nakryiko 
33957400dccSAndrii Nakryiko 	MY_PID_GUARD();
34057400dccSAndrii Nakryiko 
34157400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, 10);
34257400dccSAndrii Nakryiko 
34357400dccSAndrii Nakryiko 	while ((v = bpf_iter_num_next(&it))) {
34457400dccSAndrii Nakryiko 		bpf_printk("ITER_SEARCH_LOOP: v=%d", *v);
34557400dccSAndrii Nakryiko 
34657400dccSAndrii Nakryiko 		if (*v == 2) {
34757400dccSAndrii Nakryiko 			found = true;
34857400dccSAndrii Nakryiko 			elem = v;
34957400dccSAndrii Nakryiko 			barrier_var(elem);
35057400dccSAndrii Nakryiko 		}
35157400dccSAndrii Nakryiko 	}
35257400dccSAndrii Nakryiko 
35357400dccSAndrii Nakryiko 	/* should fail to verify if bpf_iter_num_destroy() is here */
35457400dccSAndrii Nakryiko 
35557400dccSAndrii Nakryiko 	if (found)
35657400dccSAndrii Nakryiko 		/* here found element will be wrong, we should have copied
35757400dccSAndrii Nakryiko 		 * value to a variable, but here we want to make sure we can
35857400dccSAndrii Nakryiko 		 * access memory after the loop anyways
35957400dccSAndrii Nakryiko 		 */
36057400dccSAndrii Nakryiko 		bpf_printk("ITER_SEARCH_LOOP: FOUND IT = %d!\n", *elem);
36157400dccSAndrii Nakryiko 	else
36257400dccSAndrii Nakryiko 		bpf_printk("ITER_SEARCH_LOOP: NOT FOUND IT!\n");
36357400dccSAndrii Nakryiko 
36457400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
36557400dccSAndrii Nakryiko 
36657400dccSAndrii Nakryiko 	return 0;
36757400dccSAndrii Nakryiko }
36857400dccSAndrii Nakryiko 
36957400dccSAndrii Nakryiko SEC("raw_tp")
37057400dccSAndrii Nakryiko __success
iter_array_fill(const void * ctx)37157400dccSAndrii Nakryiko int iter_array_fill(const void *ctx)
37257400dccSAndrii Nakryiko {
37357400dccSAndrii Nakryiko 	int sum, i;
37457400dccSAndrii Nakryiko 
37557400dccSAndrii Nakryiko 	MY_PID_GUARD();
37657400dccSAndrii Nakryiko 
37757400dccSAndrii Nakryiko 	bpf_for(i, 0, ARRAY_SIZE(arr)) {
37857400dccSAndrii Nakryiko 		arr[i] = i * 2;
37957400dccSAndrii Nakryiko 	}
38057400dccSAndrii Nakryiko 
38157400dccSAndrii Nakryiko 	sum = 0;
38257400dccSAndrii Nakryiko 	bpf_for(i, 0, ARRAY_SIZE(arr)) {
38357400dccSAndrii Nakryiko 		sum += arr[i];
38457400dccSAndrii Nakryiko 	}
38557400dccSAndrii Nakryiko 
38657400dccSAndrii Nakryiko 	bpf_printk("ITER_ARRAY_FILL: sum=%d (should be %d)\n", sum, 255 * 256);
38757400dccSAndrii Nakryiko 
38857400dccSAndrii Nakryiko 	return 0;
38957400dccSAndrii Nakryiko }
39057400dccSAndrii Nakryiko 
39157400dccSAndrii Nakryiko static int arr2d[4][5];
39257400dccSAndrii Nakryiko static int arr2d_row_sums[4];
39357400dccSAndrii Nakryiko static int arr2d_col_sums[5];
39457400dccSAndrii Nakryiko 
39557400dccSAndrii Nakryiko SEC("raw_tp")
39657400dccSAndrii Nakryiko __success
iter_nested_iters(const void * ctx)39757400dccSAndrii Nakryiko int iter_nested_iters(const void *ctx)
39857400dccSAndrii Nakryiko {
39957400dccSAndrii Nakryiko 	int sum, row, col;
40057400dccSAndrii Nakryiko 
40157400dccSAndrii Nakryiko 	MY_PID_GUARD();
40257400dccSAndrii Nakryiko 
40357400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
40457400dccSAndrii Nakryiko 		bpf_for( col, 0, ARRAY_SIZE(arr2d[0])) {
40557400dccSAndrii Nakryiko 			arr2d[row][col] = row * col;
40657400dccSAndrii Nakryiko 		}
40757400dccSAndrii Nakryiko 	}
40857400dccSAndrii Nakryiko 
40957400dccSAndrii Nakryiko 	/* zero-initialize sums */
41057400dccSAndrii Nakryiko 	sum = 0;
41157400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
41257400dccSAndrii Nakryiko 		arr2d_row_sums[row] = 0;
41357400dccSAndrii Nakryiko 	}
41457400dccSAndrii Nakryiko 	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
41557400dccSAndrii Nakryiko 		arr2d_col_sums[col] = 0;
41657400dccSAndrii Nakryiko 	}
41757400dccSAndrii Nakryiko 
41857400dccSAndrii Nakryiko 	/* calculate sums */
41957400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
42057400dccSAndrii Nakryiko 		bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
42157400dccSAndrii Nakryiko 			sum += arr2d[row][col];
42257400dccSAndrii Nakryiko 			arr2d_row_sums[row] += arr2d[row][col];
42357400dccSAndrii Nakryiko 			arr2d_col_sums[col] += arr2d[row][col];
42457400dccSAndrii Nakryiko 		}
42557400dccSAndrii Nakryiko 	}
42657400dccSAndrii Nakryiko 
42757400dccSAndrii Nakryiko 	bpf_printk("ITER_NESTED_ITERS: total sum=%d", sum);
42857400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
42957400dccSAndrii Nakryiko 		bpf_printk("ITER_NESTED_ITERS: row #%d sum=%d", row, arr2d_row_sums[row]);
43057400dccSAndrii Nakryiko 	}
43157400dccSAndrii Nakryiko 	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
43257400dccSAndrii Nakryiko 		bpf_printk("ITER_NESTED_ITERS: col #%d sum=%d%s",
43357400dccSAndrii Nakryiko 			   col, arr2d_col_sums[col],
43457400dccSAndrii Nakryiko 			   col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : "");
43557400dccSAndrii Nakryiko 	}
43657400dccSAndrii Nakryiko 
43757400dccSAndrii Nakryiko 	return 0;
43857400dccSAndrii Nakryiko }
43957400dccSAndrii Nakryiko 
44057400dccSAndrii Nakryiko SEC("raw_tp")
44157400dccSAndrii Nakryiko __success
iter_nested_deeply_iters(const void * ctx)44257400dccSAndrii Nakryiko int iter_nested_deeply_iters(const void *ctx)
44357400dccSAndrii Nakryiko {
44457400dccSAndrii Nakryiko 	int sum = 0;
44557400dccSAndrii Nakryiko 
44657400dccSAndrii Nakryiko 	MY_PID_GUARD();
44757400dccSAndrii Nakryiko 
44857400dccSAndrii Nakryiko 	bpf_repeat(10) {
44957400dccSAndrii Nakryiko 		bpf_repeat(10) {
45057400dccSAndrii Nakryiko 			bpf_repeat(10) {
45157400dccSAndrii Nakryiko 				bpf_repeat(10) {
45257400dccSAndrii Nakryiko 					bpf_repeat(10) {
45357400dccSAndrii Nakryiko 						sum += 1;
45457400dccSAndrii Nakryiko 					}
45557400dccSAndrii Nakryiko 				}
45657400dccSAndrii Nakryiko 			}
45757400dccSAndrii Nakryiko 		}
45857400dccSAndrii Nakryiko 		/* validate that we can break from inside bpf_repeat() */
45957400dccSAndrii Nakryiko 		break;
46057400dccSAndrii Nakryiko 	}
46157400dccSAndrii Nakryiko 
46257400dccSAndrii Nakryiko 	return sum;
46357400dccSAndrii Nakryiko }
46457400dccSAndrii Nakryiko 
fill_inner_dimension(int row)46557400dccSAndrii Nakryiko static __noinline void fill_inner_dimension(int row)
46657400dccSAndrii Nakryiko {
46757400dccSAndrii Nakryiko 	int col;
46857400dccSAndrii Nakryiko 
46957400dccSAndrii Nakryiko 	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
47057400dccSAndrii Nakryiko 		arr2d[row][col] = row * col;
47157400dccSAndrii Nakryiko 	}
47257400dccSAndrii Nakryiko }
47357400dccSAndrii Nakryiko 
sum_inner_dimension(int row)47457400dccSAndrii Nakryiko static __noinline int sum_inner_dimension(int row)
47557400dccSAndrii Nakryiko {
47657400dccSAndrii Nakryiko 	int sum = 0, col;
47757400dccSAndrii Nakryiko 
47857400dccSAndrii Nakryiko 	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
47957400dccSAndrii Nakryiko 		sum += arr2d[row][col];
48057400dccSAndrii Nakryiko 		arr2d_row_sums[row] += arr2d[row][col];
48157400dccSAndrii Nakryiko 		arr2d_col_sums[col] += arr2d[row][col];
48257400dccSAndrii Nakryiko 	}
48357400dccSAndrii Nakryiko 
48457400dccSAndrii Nakryiko 	return sum;
48557400dccSAndrii Nakryiko }
48657400dccSAndrii Nakryiko 
48757400dccSAndrii Nakryiko SEC("raw_tp")
48857400dccSAndrii Nakryiko __success
iter_subprog_iters(const void * ctx)48957400dccSAndrii Nakryiko int iter_subprog_iters(const void *ctx)
49057400dccSAndrii Nakryiko {
49157400dccSAndrii Nakryiko 	int sum, row, col;
49257400dccSAndrii Nakryiko 
49357400dccSAndrii Nakryiko 	MY_PID_GUARD();
49457400dccSAndrii Nakryiko 
49557400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
49657400dccSAndrii Nakryiko 		fill_inner_dimension(row);
49757400dccSAndrii Nakryiko 	}
49857400dccSAndrii Nakryiko 
49957400dccSAndrii Nakryiko 	/* zero-initialize sums */
50057400dccSAndrii Nakryiko 	sum = 0;
50157400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
50257400dccSAndrii Nakryiko 		arr2d_row_sums[row] = 0;
50357400dccSAndrii Nakryiko 	}
50457400dccSAndrii Nakryiko 	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
50557400dccSAndrii Nakryiko 		arr2d_col_sums[col] = 0;
50657400dccSAndrii Nakryiko 	}
50757400dccSAndrii Nakryiko 
50857400dccSAndrii Nakryiko 	/* calculate sums */
50957400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
51057400dccSAndrii Nakryiko 		sum += sum_inner_dimension(row);
51157400dccSAndrii Nakryiko 	}
51257400dccSAndrii Nakryiko 
51357400dccSAndrii Nakryiko 	bpf_printk("ITER_SUBPROG_ITERS: total sum=%d", sum);
51457400dccSAndrii Nakryiko 	bpf_for(row, 0, ARRAY_SIZE(arr2d)) {
51557400dccSAndrii Nakryiko 		bpf_printk("ITER_SUBPROG_ITERS: row #%d sum=%d",
51657400dccSAndrii Nakryiko 			   row, arr2d_row_sums[row]);
51757400dccSAndrii Nakryiko 	}
51857400dccSAndrii Nakryiko 	bpf_for(col, 0, ARRAY_SIZE(arr2d[0])) {
51957400dccSAndrii Nakryiko 		bpf_printk("ITER_SUBPROG_ITERS: col #%d sum=%d%s",
52057400dccSAndrii Nakryiko 			   col, arr2d_col_sums[col],
52157400dccSAndrii Nakryiko 			   col == ARRAY_SIZE(arr2d[0]) - 1 ? "\n" : "");
52257400dccSAndrii Nakryiko 	}
52357400dccSAndrii Nakryiko 
52457400dccSAndrii Nakryiko 	return 0;
52557400dccSAndrii Nakryiko }
52657400dccSAndrii Nakryiko 
52757400dccSAndrii Nakryiko struct {
52857400dccSAndrii Nakryiko 	__uint(type, BPF_MAP_TYPE_ARRAY);
52957400dccSAndrii Nakryiko 	__type(key, int);
53057400dccSAndrii Nakryiko 	__type(value, int);
53157400dccSAndrii Nakryiko 	__uint(max_entries, 1000);
53257400dccSAndrii Nakryiko } arr_map SEC(".maps");
53357400dccSAndrii Nakryiko 
53457400dccSAndrii Nakryiko SEC("?raw_tp")
53557400dccSAndrii Nakryiko __failure __msg("invalid mem access 'scalar'")
iter_err_too_permissive1(const void * ctx)53657400dccSAndrii Nakryiko int iter_err_too_permissive1(const void *ctx)
53757400dccSAndrii Nakryiko {
53857400dccSAndrii Nakryiko 	int *map_val = NULL;
53957400dccSAndrii Nakryiko 	int key = 0;
54057400dccSAndrii Nakryiko 
54157400dccSAndrii Nakryiko 	MY_PID_GUARD();
54257400dccSAndrii Nakryiko 
54357400dccSAndrii Nakryiko 	map_val = bpf_map_lookup_elem(&arr_map, &key);
54457400dccSAndrii Nakryiko 	if (!map_val)
54557400dccSAndrii Nakryiko 		return 0;
54657400dccSAndrii Nakryiko 
54757400dccSAndrii Nakryiko 	bpf_repeat(1000000) {
54857400dccSAndrii Nakryiko 		map_val = NULL;
54957400dccSAndrii Nakryiko 	}
55057400dccSAndrii Nakryiko 
55157400dccSAndrii Nakryiko 	*map_val = 123;
55257400dccSAndrii Nakryiko 
55357400dccSAndrii Nakryiko 	return 0;
55457400dccSAndrii Nakryiko }
55557400dccSAndrii Nakryiko 
55657400dccSAndrii Nakryiko SEC("?raw_tp")
55757400dccSAndrii Nakryiko __failure __msg("invalid mem access 'map_value_or_null'")
iter_err_too_permissive2(const void * ctx)55857400dccSAndrii Nakryiko int iter_err_too_permissive2(const void *ctx)
55957400dccSAndrii Nakryiko {
56057400dccSAndrii Nakryiko 	int *map_val = NULL;
56157400dccSAndrii Nakryiko 	int key = 0;
56257400dccSAndrii Nakryiko 
56357400dccSAndrii Nakryiko 	MY_PID_GUARD();
56457400dccSAndrii Nakryiko 
56557400dccSAndrii Nakryiko 	map_val = bpf_map_lookup_elem(&arr_map, &key);
56657400dccSAndrii Nakryiko 	if (!map_val)
56757400dccSAndrii Nakryiko 		return 0;
56857400dccSAndrii Nakryiko 
56957400dccSAndrii Nakryiko 	bpf_repeat(1000000) {
57057400dccSAndrii Nakryiko 		map_val = bpf_map_lookup_elem(&arr_map, &key);
57157400dccSAndrii Nakryiko 	}
57257400dccSAndrii Nakryiko 
57357400dccSAndrii Nakryiko 	*map_val = 123;
57457400dccSAndrii Nakryiko 
57557400dccSAndrii Nakryiko 	return 0;
57657400dccSAndrii Nakryiko }
57757400dccSAndrii Nakryiko 
57857400dccSAndrii Nakryiko SEC("?raw_tp")
57957400dccSAndrii Nakryiko __failure __msg("invalid mem access 'map_value_or_null'")
iter_err_too_permissive3(const void * ctx)58057400dccSAndrii Nakryiko int iter_err_too_permissive3(const void *ctx)
58157400dccSAndrii Nakryiko {
58257400dccSAndrii Nakryiko 	int *map_val = NULL;
58357400dccSAndrii Nakryiko 	int key = 0;
58457400dccSAndrii Nakryiko 	bool found = false;
58557400dccSAndrii Nakryiko 
58657400dccSAndrii Nakryiko 	MY_PID_GUARD();
58757400dccSAndrii Nakryiko 
58857400dccSAndrii Nakryiko 	bpf_repeat(1000000) {
58957400dccSAndrii Nakryiko 		map_val = bpf_map_lookup_elem(&arr_map, &key);
59057400dccSAndrii Nakryiko 		found = true;
59157400dccSAndrii Nakryiko 	}
59257400dccSAndrii Nakryiko 
59357400dccSAndrii Nakryiko 	if (found)
59457400dccSAndrii Nakryiko 		*map_val = 123;
59557400dccSAndrii Nakryiko 
59657400dccSAndrii Nakryiko 	return 0;
59757400dccSAndrii Nakryiko }
59857400dccSAndrii Nakryiko 
59957400dccSAndrii Nakryiko SEC("raw_tp")
60057400dccSAndrii Nakryiko __success
iter_tricky_but_fine(const void * ctx)60157400dccSAndrii Nakryiko int iter_tricky_but_fine(const void *ctx)
60257400dccSAndrii Nakryiko {
60357400dccSAndrii Nakryiko 	int *map_val = NULL;
60457400dccSAndrii Nakryiko 	int key = 0;
60557400dccSAndrii Nakryiko 	bool found = false;
60657400dccSAndrii Nakryiko 
60757400dccSAndrii Nakryiko 	MY_PID_GUARD();
60857400dccSAndrii Nakryiko 
60957400dccSAndrii Nakryiko 	bpf_repeat(1000000) {
61057400dccSAndrii Nakryiko 		map_val = bpf_map_lookup_elem(&arr_map, &key);
61157400dccSAndrii Nakryiko 		if (map_val) {
61257400dccSAndrii Nakryiko 			found = true;
61357400dccSAndrii Nakryiko 			break;
61457400dccSAndrii Nakryiko 		}
61557400dccSAndrii Nakryiko 	}
61657400dccSAndrii Nakryiko 
61757400dccSAndrii Nakryiko 	if (found)
61857400dccSAndrii Nakryiko 		*map_val = 123;
61957400dccSAndrii Nakryiko 
62057400dccSAndrii Nakryiko 	return 0;
62157400dccSAndrii Nakryiko }
62257400dccSAndrii Nakryiko 
62357400dccSAndrii Nakryiko #define __bpf_memzero(p, sz) bpf_probe_read_kernel((p), (sz), 0)
62457400dccSAndrii Nakryiko 
62557400dccSAndrii Nakryiko SEC("raw_tp")
62657400dccSAndrii Nakryiko __success
iter_stack_array_loop(const void * ctx)62757400dccSAndrii Nakryiko int iter_stack_array_loop(const void *ctx)
62857400dccSAndrii Nakryiko {
62957400dccSAndrii Nakryiko 	long arr1[16], arr2[16], sum = 0;
630c8ed6685SAndrii Nakryiko 	int i;
63157400dccSAndrii Nakryiko 
63257400dccSAndrii Nakryiko 	MY_PID_GUARD();
63357400dccSAndrii Nakryiko 
63457400dccSAndrii Nakryiko 	/* zero-init arr1 and arr2 in such a way that verifier doesn't know
63557400dccSAndrii Nakryiko 	 * it's all zeros; if we don't do that, we'll make BPF verifier track
63657400dccSAndrii Nakryiko 	 * all combination of zero/non-zero stack slots for arr1/arr2, which
63757400dccSAndrii Nakryiko 	 * will lead to O(2^(ARRAY_SIZE(arr1)+ARRAY_SIZE(arr2))) different
63857400dccSAndrii Nakryiko 	 * states
63957400dccSAndrii Nakryiko 	 */
64057400dccSAndrii Nakryiko 	__bpf_memzero(arr1, sizeof(arr1));
64157400dccSAndrii Nakryiko 	__bpf_memzero(arr2, sizeof(arr1));
64257400dccSAndrii Nakryiko 
64357400dccSAndrii Nakryiko 	/* validate that we can break and continue when using bpf_for() */
64457400dccSAndrii Nakryiko 	bpf_for(i, 0, ARRAY_SIZE(arr1)) {
64557400dccSAndrii Nakryiko 		if (i & 1) {
64657400dccSAndrii Nakryiko 			arr1[i] = i;
64757400dccSAndrii Nakryiko 			continue;
64857400dccSAndrii Nakryiko 		} else {
64957400dccSAndrii Nakryiko 			arr2[i] = i;
65057400dccSAndrii Nakryiko 			break;
65157400dccSAndrii Nakryiko 		}
65257400dccSAndrii Nakryiko 	}
65357400dccSAndrii Nakryiko 
65457400dccSAndrii Nakryiko 	bpf_for(i, 0, ARRAY_SIZE(arr1)) {
65557400dccSAndrii Nakryiko 		sum += arr1[i] + arr2[i];
65657400dccSAndrii Nakryiko 	}
65757400dccSAndrii Nakryiko 
65857400dccSAndrii Nakryiko 	return sum;
65957400dccSAndrii Nakryiko }
66057400dccSAndrii Nakryiko 
fill(struct bpf_iter_num * it,int * arr,__u32 n,int mul)661c91ab90cSAndrii Nakryiko static __noinline void fill(struct bpf_iter_num *it, int *arr, __u32 n, int mul)
66257400dccSAndrii Nakryiko {
663c91ab90cSAndrii Nakryiko 	int *t, i;
66457400dccSAndrii Nakryiko 
66557400dccSAndrii Nakryiko 	while ((t = bpf_iter_num_next(it))) {
66657400dccSAndrii Nakryiko 		i = *t;
667c91ab90cSAndrii Nakryiko 		if (i >= n)
66857400dccSAndrii Nakryiko 			break;
66957400dccSAndrii Nakryiko 		arr[i] =  i * mul;
67057400dccSAndrii Nakryiko 	}
67157400dccSAndrii Nakryiko }
67257400dccSAndrii Nakryiko 
sum(struct bpf_iter_num * it,int * arr,__u32 n)673c91ab90cSAndrii Nakryiko static __noinline int sum(struct bpf_iter_num *it, int *arr, __u32 n)
67457400dccSAndrii Nakryiko {
675c91ab90cSAndrii Nakryiko 	int *t, i, sum = 0;;
67657400dccSAndrii Nakryiko 
67757400dccSAndrii Nakryiko 	while ((t = bpf_iter_num_next(it))) {
67857400dccSAndrii Nakryiko 		i = *t;
679c91ab90cSAndrii Nakryiko 		if (i >= n)
68057400dccSAndrii Nakryiko 			break;
68157400dccSAndrii Nakryiko 		sum += arr[i];
68257400dccSAndrii Nakryiko 	}
68357400dccSAndrii Nakryiko 
68457400dccSAndrii Nakryiko 	return sum;
68557400dccSAndrii Nakryiko }
68657400dccSAndrii Nakryiko 
68757400dccSAndrii Nakryiko SEC("raw_tp")
68857400dccSAndrii Nakryiko __success
iter_pass_iter_ptr_to_subprog(const void * ctx)68957400dccSAndrii Nakryiko int iter_pass_iter_ptr_to_subprog(const void *ctx)
69057400dccSAndrii Nakryiko {
691c91ab90cSAndrii Nakryiko 	int arr1[16], arr2[32];
69257400dccSAndrii Nakryiko 	struct bpf_iter_num it;
69357400dccSAndrii Nakryiko 	int n, sum1, sum2;
69457400dccSAndrii Nakryiko 
69557400dccSAndrii Nakryiko 	MY_PID_GUARD();
69657400dccSAndrii Nakryiko 
69757400dccSAndrii Nakryiko 	/* fill arr1 */
69857400dccSAndrii Nakryiko 	n = ARRAY_SIZE(arr1);
69957400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, n);
700c91ab90cSAndrii Nakryiko 	fill(&it, arr1, n, 2);
70157400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
70257400dccSAndrii Nakryiko 
70357400dccSAndrii Nakryiko 	/* fill arr2 */
70457400dccSAndrii Nakryiko 	n = ARRAY_SIZE(arr2);
70557400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, n);
706c91ab90cSAndrii Nakryiko 	fill(&it, arr2, n, 10);
70757400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
70857400dccSAndrii Nakryiko 
70957400dccSAndrii Nakryiko 	/* sum arr1 */
71057400dccSAndrii Nakryiko 	n = ARRAY_SIZE(arr1);
71157400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, n);
712c91ab90cSAndrii Nakryiko 	sum1 = sum(&it, arr1, n);
71357400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
71457400dccSAndrii Nakryiko 
71557400dccSAndrii Nakryiko 	/* sum arr2 */
71657400dccSAndrii Nakryiko 	n = ARRAY_SIZE(arr2);
71757400dccSAndrii Nakryiko 	bpf_iter_num_new(&it, 0, n);
718c91ab90cSAndrii Nakryiko 	sum2 = sum(&it, arr2, n);
71957400dccSAndrii Nakryiko 	bpf_iter_num_destroy(&it);
72057400dccSAndrii Nakryiko 
72157400dccSAndrii Nakryiko 	bpf_printk("sum1=%d, sum2=%d", sum1, sum2);
72257400dccSAndrii Nakryiko 
72357400dccSAndrii Nakryiko 	return 0;
72457400dccSAndrii Nakryiko }
72557400dccSAndrii Nakryiko 
7267f764ea0SEduard Zingerman SEC("?raw_tp")
7277f764ea0SEduard Zingerman __failure
7287f764ea0SEduard Zingerman __msg("R1 type=scalar expected=fp")
delayed_read_mark(void)7297f764ea0SEduard Zingerman __naked int delayed_read_mark(void)
7307f764ea0SEduard Zingerman {
7317f764ea0SEduard Zingerman 	/* This is equivalent to C program below.
7327f764ea0SEduard Zingerman 	 * The call to bpf_iter_num_next() is reachable with r7 values &fp[-16] and 0xdead.
7337f764ea0SEduard Zingerman 	 * State with r7=&fp[-16] is visited first and follows r6 != 42 ... continue branch.
7347f764ea0SEduard Zingerman 	 * At this point iterator next() call is reached with r7 that has no read mark.
7357f764ea0SEduard Zingerman 	 * Loop body with r7=0xdead would only be visited if verifier would decide to continue
7367f764ea0SEduard Zingerman 	 * with second loop iteration. Absence of read mark on r7 might affect state
7377f764ea0SEduard Zingerman 	 * equivalent logic used for iterator convergence tracking.
7387f764ea0SEduard Zingerman 	 *
7397f764ea0SEduard Zingerman 	 * r7 = &fp[-16]
7407f764ea0SEduard Zingerman 	 * fp[-16] = 0
7417f764ea0SEduard Zingerman 	 * r6 = bpf_get_prandom_u32()
7427f764ea0SEduard Zingerman 	 * bpf_iter_num_new(&fp[-8], 0, 10)
7437f764ea0SEduard Zingerman 	 * while (bpf_iter_num_next(&fp[-8])) {
7447f764ea0SEduard Zingerman 	 *   r6++
7457f764ea0SEduard Zingerman 	 *   if (r6 != 42) {
7467f764ea0SEduard Zingerman 	 *     r7 = 0xdead
7477f764ea0SEduard Zingerman 	 *     continue;
7487f764ea0SEduard Zingerman 	 *   }
7497f764ea0SEduard Zingerman 	 *   bpf_probe_read_user(r7, 8, 0xdeadbeef); // this is not safe
7507f764ea0SEduard Zingerman 	 * }
7517f764ea0SEduard Zingerman 	 * bpf_iter_num_destroy(&fp[-8])
7527f764ea0SEduard Zingerman 	 * return 0
7537f764ea0SEduard Zingerman 	 */
7547f764ea0SEduard Zingerman 	asm volatile (
7557f764ea0SEduard Zingerman 		"r7 = r10;"
7567f764ea0SEduard Zingerman 		"r7 += -16;"
7577f764ea0SEduard Zingerman 		"r0 = 0;"
7587f764ea0SEduard Zingerman 		"*(u64 *)(r7 + 0) = r0;"
7597f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
7607f764ea0SEduard Zingerman 		"r6 = r0;"
7617f764ea0SEduard Zingerman 		"r1 = r10;"
7627f764ea0SEduard Zingerman 		"r1 += -8;"
7637f764ea0SEduard Zingerman 		"r2 = 0;"
7647f764ea0SEduard Zingerman 		"r3 = 10;"
7657f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
7667f764ea0SEduard Zingerman 	"1:"
7677f764ea0SEduard Zingerman 		"r1 = r10;"
7687f764ea0SEduard Zingerman 		"r1 += -8;"
7697f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
7707f764ea0SEduard Zingerman 		"if r0 == 0 goto 2f;"
7717f764ea0SEduard Zingerman 		"r6 += 1;"
7727f764ea0SEduard Zingerman 		"if r6 != 42 goto 3f;"
7737f764ea0SEduard Zingerman 		"r7 = 0xdead;"
7747f764ea0SEduard Zingerman 		"goto 1b;"
7757f764ea0SEduard Zingerman 	"3:"
7767f764ea0SEduard Zingerman 		"r1 = r7;"
7777f764ea0SEduard Zingerman 		"r2 = 8;"
7787f764ea0SEduard Zingerman 		"r3 = 0xdeadbeef;"
7797f764ea0SEduard Zingerman 		"call %[bpf_probe_read_user];"
7807f764ea0SEduard Zingerman 		"goto 1b;"
7817f764ea0SEduard Zingerman 	"2:"
7827f764ea0SEduard Zingerman 		"r1 = r10;"
7837f764ea0SEduard Zingerman 		"r1 += -8;"
7847f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
7857f764ea0SEduard Zingerman 		"r0 = 0;"
7867f764ea0SEduard Zingerman 		"exit;"
7877f764ea0SEduard Zingerman 		:
7887f764ea0SEduard Zingerman 		: __imm(bpf_get_prandom_u32),
7897f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_new),
7907f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_next),
7917f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_destroy),
7927f764ea0SEduard Zingerman 		  __imm(bpf_probe_read_user)
7937f764ea0SEduard Zingerman 		: __clobber_all
7947f764ea0SEduard Zingerman 	);
7957f764ea0SEduard Zingerman }
7967f764ea0SEduard Zingerman 
7977f764ea0SEduard Zingerman SEC("?raw_tp")
7987f764ea0SEduard Zingerman __failure
7997f764ea0SEduard Zingerman __msg("math between fp pointer and register with unbounded")
delayed_precision_mark(void)8007f764ea0SEduard Zingerman __naked int delayed_precision_mark(void)
8017f764ea0SEduard Zingerman {
8027f764ea0SEduard Zingerman 	/* This is equivalent to C program below.
8037f764ea0SEduard Zingerman 	 * The test is similar to delayed_iter_mark but verifies that incomplete
8047f764ea0SEduard Zingerman 	 * precision don't fool verifier.
8057f764ea0SEduard Zingerman 	 * The call to bpf_iter_num_next() is reachable with r7 values -16 and -32.
8067f764ea0SEduard Zingerman 	 * State with r7=-16 is visited first and follows r6 != 42 ... continue branch.
8077f764ea0SEduard Zingerman 	 * At this point iterator next() call is reached with r7 that has no read
8087f764ea0SEduard Zingerman 	 * and precision marks.
8097f764ea0SEduard Zingerman 	 * Loop body with r7=-32 would only be visited if verifier would decide to continue
8107f764ea0SEduard Zingerman 	 * with second loop iteration. Absence of precision mark on r7 might affect state
8117f764ea0SEduard Zingerman 	 * equivalent logic used for iterator convergence tracking.
8127f764ea0SEduard Zingerman 	 *
8137f764ea0SEduard Zingerman 	 * r8 = 0
8147f764ea0SEduard Zingerman 	 * fp[-16] = 0
8157f764ea0SEduard Zingerman 	 * r7 = -16
8167f764ea0SEduard Zingerman 	 * r6 = bpf_get_prandom_u32()
8177f764ea0SEduard Zingerman 	 * bpf_iter_num_new(&fp[-8], 0, 10)
8187f764ea0SEduard Zingerman 	 * while (bpf_iter_num_next(&fp[-8])) {
8197f764ea0SEduard Zingerman 	 *   if (r6 != 42) {
8207f764ea0SEduard Zingerman 	 *     r7 = -32
8217f764ea0SEduard Zingerman 	 *     r6 = bpf_get_prandom_u32()
8227f764ea0SEduard Zingerman 	 *     continue;
8237f764ea0SEduard Zingerman 	 *   }
8247f764ea0SEduard Zingerman 	 *   r0 = r10
8257f764ea0SEduard Zingerman 	 *   r0 += r7
8267f764ea0SEduard Zingerman 	 *   r8 = *(u64 *)(r0 + 0)           // this is not safe
8277f764ea0SEduard Zingerman 	 *   r6 = bpf_get_prandom_u32()
8287f764ea0SEduard Zingerman 	 * }
8297f764ea0SEduard Zingerman 	 * bpf_iter_num_destroy(&fp[-8])
8307f764ea0SEduard Zingerman 	 * return r8
8317f764ea0SEduard Zingerman 	 */
8327f764ea0SEduard Zingerman 	asm volatile (
8337f764ea0SEduard Zingerman 		"r8 = 0;"
8347f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 16) = r8;"
8357f764ea0SEduard Zingerman 		"r7 = -16;"
8367f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
8377f764ea0SEduard Zingerman 		"r6 = r0;"
8387f764ea0SEduard Zingerman 		"r1 = r10;"
8397f764ea0SEduard Zingerman 		"r1 += -8;"
8407f764ea0SEduard Zingerman 		"r2 = 0;"
8417f764ea0SEduard Zingerman 		"r3 = 10;"
8427f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
8437f764ea0SEduard Zingerman 	"1:"
8447f764ea0SEduard Zingerman 		"r1 = r10;"
8457f764ea0SEduard Zingerman 		"r1 += -8;\n"
8467f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
8477f764ea0SEduard Zingerman 		"if r0 == 0 goto 2f;"
8487f764ea0SEduard Zingerman 		"if r6 != 42 goto 3f;"
8497f764ea0SEduard Zingerman 		"r7 = -32;"
8507f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
8517f764ea0SEduard Zingerman 		"r6 = r0;"
8527f764ea0SEduard Zingerman 		"goto 1b;\n"
8537f764ea0SEduard Zingerman 	"3:"
8547f764ea0SEduard Zingerman 		"r0 = r10;"
8557f764ea0SEduard Zingerman 		"r0 += r7;"
8567f764ea0SEduard Zingerman 		"r8 = *(u64 *)(r0 + 0);"
8577f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
8587f764ea0SEduard Zingerman 		"r6 = r0;"
8597f764ea0SEduard Zingerman 		"goto 1b;\n"
8607f764ea0SEduard Zingerman 	"2:"
8617f764ea0SEduard Zingerman 		"r1 = r10;"
8627f764ea0SEduard Zingerman 		"r1 += -8;"
8637f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
8647f764ea0SEduard Zingerman 		"r0 = r8;"
8657f764ea0SEduard Zingerman 		"exit;"
8667f764ea0SEduard Zingerman 		:
8677f764ea0SEduard Zingerman 		: __imm(bpf_get_prandom_u32),
8687f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_new),
8697f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_next),
8707f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_destroy),
8717f764ea0SEduard Zingerman 		  __imm(bpf_probe_read_user)
8727f764ea0SEduard Zingerman 		: __clobber_all
8737f764ea0SEduard Zingerman 	);
8747f764ea0SEduard Zingerman }
8757f764ea0SEduard Zingerman 
8767f764ea0SEduard Zingerman SEC("?raw_tp")
8777f764ea0SEduard Zingerman __failure
8787f764ea0SEduard Zingerman __msg("math between fp pointer and register with unbounded")
__flag(BPF_F_TEST_STATE_FREQ)8797f764ea0SEduard Zingerman __flag(BPF_F_TEST_STATE_FREQ)
8807f764ea0SEduard Zingerman __naked int loop_state_deps1(void)
8817f764ea0SEduard Zingerman {
8827f764ea0SEduard Zingerman 	/* This is equivalent to C program below.
8837f764ea0SEduard Zingerman 	 *
8847f764ea0SEduard Zingerman 	 * The case turns out to be tricky in a sense that:
8857f764ea0SEduard Zingerman 	 * - states with c=-25 are explored only on a second iteration
8867f764ea0SEduard Zingerman 	 *   of the outer loop;
8877f764ea0SEduard Zingerman 	 * - states with read+precise mark on c are explored only on
8887f764ea0SEduard Zingerman 	 *   second iteration of the inner loop and in a state which
8897f764ea0SEduard Zingerman 	 *   is pushed to states stack first.
8907f764ea0SEduard Zingerman 	 *
8917f764ea0SEduard Zingerman 	 * Depending on the details of iterator convergence logic
8927f764ea0SEduard Zingerman 	 * verifier might stop states traversal too early and miss
8937f764ea0SEduard Zingerman 	 * unsafe c=-25 memory access.
8947f764ea0SEduard Zingerman 	 *
8957f764ea0SEduard Zingerman 	 *   j = iter_new();		 // fp[-16]
8967f764ea0SEduard Zingerman 	 *   a = 0;			 // r6
8977f764ea0SEduard Zingerman 	 *   b = 0;			 // r7
8987f764ea0SEduard Zingerman 	 *   c = -24;			 // r8
8997f764ea0SEduard Zingerman 	 *   while (iter_next(j)) {
9007f764ea0SEduard Zingerman 	 *     i = iter_new();		 // fp[-8]
9017f764ea0SEduard Zingerman 	 *     a = 0;			 // r6
9027f764ea0SEduard Zingerman 	 *     b = 0;			 // r7
9037f764ea0SEduard Zingerman 	 *     while (iter_next(i)) {
9047f764ea0SEduard Zingerman 	 *	 if (a == 1) {
9057f764ea0SEduard Zingerman 	 *	   a = 0;
9067f764ea0SEduard Zingerman 	 *	   b = 1;
9077f764ea0SEduard Zingerman 	 *	 } else if (a == 0) {
9087f764ea0SEduard Zingerman 	 *	   a = 1;
9097f764ea0SEduard Zingerman 	 *	   if (random() == 42)
9107f764ea0SEduard Zingerman 	 *	     continue;
9117f764ea0SEduard Zingerman 	 *	   if (b == 1) {
9127f764ea0SEduard Zingerman 	 *	     *(r10 + c) = 7;  // this is not safe
9137f764ea0SEduard Zingerman 	 *	     iter_destroy(i);
9147f764ea0SEduard Zingerman 	 *	     iter_destroy(j);
9157f764ea0SEduard Zingerman 	 *	     return;
9167f764ea0SEduard Zingerman 	 *	   }
9177f764ea0SEduard Zingerman 	 *	 }
9187f764ea0SEduard Zingerman 	 *     }
9197f764ea0SEduard Zingerman 	 *     iter_destroy(i);
9207f764ea0SEduard Zingerman 	 *     a = 0;
9217f764ea0SEduard Zingerman 	 *     b = 0;
9227f764ea0SEduard Zingerman 	 *     c = -25;
9237f764ea0SEduard Zingerman 	 *   }
9247f764ea0SEduard Zingerman 	 *   iter_destroy(j);
9257f764ea0SEduard Zingerman 	 *   return;
9267f764ea0SEduard Zingerman 	 */
9277f764ea0SEduard Zingerman 	asm volatile (
9287f764ea0SEduard Zingerman 		"r1 = r10;"
9297f764ea0SEduard Zingerman 		"r1 += -16;"
9307f764ea0SEduard Zingerman 		"r2 = 0;"
9317f764ea0SEduard Zingerman 		"r3 = 10;"
9327f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
9337f764ea0SEduard Zingerman 		"r6 = 0;"
9347f764ea0SEduard Zingerman 		"r7 = 0;"
9357f764ea0SEduard Zingerman 		"r8 = -24;"
9367f764ea0SEduard Zingerman 	"j_loop_%=:"
9377f764ea0SEduard Zingerman 		"r1 = r10;"
9387f764ea0SEduard Zingerman 		"r1 += -16;"
9397f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
9407f764ea0SEduard Zingerman 		"if r0 == 0 goto j_loop_end_%=;"
9417f764ea0SEduard Zingerman 		"r1 = r10;"
9427f764ea0SEduard Zingerman 		"r1 += -8;"
9437f764ea0SEduard Zingerman 		"r2 = 0;"
9447f764ea0SEduard Zingerman 		"r3 = 10;"
9457f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
9467f764ea0SEduard Zingerman 		"r6 = 0;"
9477f764ea0SEduard Zingerman 		"r7 = 0;"
9487f764ea0SEduard Zingerman 	"i_loop_%=:"
9497f764ea0SEduard Zingerman 		"r1 = r10;"
9507f764ea0SEduard Zingerman 		"r1 += -8;"
9517f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
9527f764ea0SEduard Zingerman 		"if r0 == 0 goto i_loop_end_%=;"
9537f764ea0SEduard Zingerman 	"check_one_r6_%=:"
9547f764ea0SEduard Zingerman 		"if r6 != 1 goto check_zero_r6_%=;"
9557f764ea0SEduard Zingerman 		"r6 = 0;"
9567f764ea0SEduard Zingerman 		"r7 = 1;"
9577f764ea0SEduard Zingerman 		"goto i_loop_%=;"
9587f764ea0SEduard Zingerman 	"check_zero_r6_%=:"
9597f764ea0SEduard Zingerman 		"if r6 != 0 goto i_loop_%=;"
9607f764ea0SEduard Zingerman 		"r6 = 1;"
9617f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
9627f764ea0SEduard Zingerman 		"if r0 != 42 goto check_one_r7_%=;"
9637f764ea0SEduard Zingerman 		"goto i_loop_%=;"
9647f764ea0SEduard Zingerman 	"check_one_r7_%=:"
9657f764ea0SEduard Zingerman 		"if r7 != 1 goto i_loop_%=;"
9667f764ea0SEduard Zingerman 		"r0 = r10;"
9677f764ea0SEduard Zingerman 		"r0 += r8;"
9687f764ea0SEduard Zingerman 		"r1 = 7;"
9697f764ea0SEduard Zingerman 		"*(u64 *)(r0 + 0) = r1;"
9707f764ea0SEduard Zingerman 		"r1 = r10;"
9717f764ea0SEduard Zingerman 		"r1 += -8;"
9727f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
9737f764ea0SEduard Zingerman 		"r1 = r10;"
9747f764ea0SEduard Zingerman 		"r1 += -16;"
9757f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
9767f764ea0SEduard Zingerman 		"r0 = 0;"
9777f764ea0SEduard Zingerman 		"exit;"
9787f764ea0SEduard Zingerman 	"i_loop_end_%=:"
9797f764ea0SEduard Zingerman 		"r1 = r10;"
9807f764ea0SEduard Zingerman 		"r1 += -8;"
9817f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
9827f764ea0SEduard Zingerman 		"r6 = 0;"
9837f764ea0SEduard Zingerman 		"r7 = 0;"
9847f764ea0SEduard Zingerman 		"r8 = -25;"
9857f764ea0SEduard Zingerman 		"goto j_loop_%=;"
9867f764ea0SEduard Zingerman 	"j_loop_end_%=:"
9877f764ea0SEduard Zingerman 		"r1 = r10;"
9887f764ea0SEduard Zingerman 		"r1 += -16;"
9897f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
9907f764ea0SEduard Zingerman 		"r0 = 0;"
9917f764ea0SEduard Zingerman 		"exit;"
9927f764ea0SEduard Zingerman 		:
9937f764ea0SEduard Zingerman 		: __imm(bpf_get_prandom_u32),
9947f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_new),
9957f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_next),
9967f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_destroy)
9977f764ea0SEduard Zingerman 		: __clobber_all
9987f764ea0SEduard Zingerman 	);
9997f764ea0SEduard Zingerman }
10007f764ea0SEduard Zingerman 
10017f764ea0SEduard Zingerman SEC("?raw_tp")
1002*00808be7SEduard Zingerman __failure
1003*00808be7SEduard Zingerman __msg("math between fp pointer and register with unbounded")
__flag(BPF_F_TEST_STATE_FREQ)1004*00808be7SEduard Zingerman __flag(BPF_F_TEST_STATE_FREQ)
1005*00808be7SEduard Zingerman __naked int loop_state_deps2(void)
1006*00808be7SEduard Zingerman {
1007*00808be7SEduard Zingerman 	/* This is equivalent to C program below.
1008*00808be7SEduard Zingerman 	 *
1009*00808be7SEduard Zingerman 	 * The case turns out to be tricky in a sense that:
1010*00808be7SEduard Zingerman 	 * - states with read+precise mark on c are explored only on a second
1011*00808be7SEduard Zingerman 	 *   iteration of the first inner loop and in a state which is pushed to
1012*00808be7SEduard Zingerman 	 *   states stack first.
1013*00808be7SEduard Zingerman 	 * - states with c=-25 are explored only on a second iteration of the
1014*00808be7SEduard Zingerman 	 *   second inner loop and in a state which is pushed to states stack
1015*00808be7SEduard Zingerman 	 *   first.
1016*00808be7SEduard Zingerman 	 *
1017*00808be7SEduard Zingerman 	 * Depending on the details of iterator convergence logic
1018*00808be7SEduard Zingerman 	 * verifier might stop states traversal too early and miss
1019*00808be7SEduard Zingerman 	 * unsafe c=-25 memory access.
1020*00808be7SEduard Zingerman 	 *
1021*00808be7SEduard Zingerman 	 *   j = iter_new();             // fp[-16]
1022*00808be7SEduard Zingerman 	 *   a = 0;                      // r6
1023*00808be7SEduard Zingerman 	 *   b = 0;                      // r7
1024*00808be7SEduard Zingerman 	 *   c = -24;                    // r8
1025*00808be7SEduard Zingerman 	 *   while (iter_next(j)) {
1026*00808be7SEduard Zingerman 	 *     i = iter_new();           // fp[-8]
1027*00808be7SEduard Zingerman 	 *     a = 0;                    // r6
1028*00808be7SEduard Zingerman 	 *     b = 0;                    // r7
1029*00808be7SEduard Zingerman 	 *     while (iter_next(i)) {
1030*00808be7SEduard Zingerman 	 *       if (a == 1) {
1031*00808be7SEduard Zingerman 	 *         a = 0;
1032*00808be7SEduard Zingerman 	 *         b = 1;
1033*00808be7SEduard Zingerman 	 *       } else if (a == 0) {
1034*00808be7SEduard Zingerman 	 *         a = 1;
1035*00808be7SEduard Zingerman 	 *         if (random() == 42)
1036*00808be7SEduard Zingerman 	 *           continue;
1037*00808be7SEduard Zingerman 	 *         if (b == 1) {
1038*00808be7SEduard Zingerman 	 *           *(r10 + c) = 7;     // this is not safe
1039*00808be7SEduard Zingerman 	 *           iter_destroy(i);
1040*00808be7SEduard Zingerman 	 *           iter_destroy(j);
1041*00808be7SEduard Zingerman 	 *           return;
1042*00808be7SEduard Zingerman 	 *         }
1043*00808be7SEduard Zingerman 	 *       }
1044*00808be7SEduard Zingerman 	 *     }
1045*00808be7SEduard Zingerman 	 *     iter_destroy(i);
1046*00808be7SEduard Zingerman 	 *     i = iter_new();           // fp[-8]
1047*00808be7SEduard Zingerman 	 *     a = 0;                    // r6
1048*00808be7SEduard Zingerman 	 *     b = 0;                    // r7
1049*00808be7SEduard Zingerman 	 *     while (iter_next(i)) {
1050*00808be7SEduard Zingerman 	 *       if (a == 1) {
1051*00808be7SEduard Zingerman 	 *         a = 0;
1052*00808be7SEduard Zingerman 	 *         b = 1;
1053*00808be7SEduard Zingerman 	 *       } else if (a == 0) {
1054*00808be7SEduard Zingerman 	 *         a = 1;
1055*00808be7SEduard Zingerman 	 *         if (random() == 42)
1056*00808be7SEduard Zingerman 	 *           continue;
1057*00808be7SEduard Zingerman 	 *         if (b == 1) {
1058*00808be7SEduard Zingerman 	 *           a = 0;
1059*00808be7SEduard Zingerman 	 *           c = -25;
1060*00808be7SEduard Zingerman 	 *         }
1061*00808be7SEduard Zingerman 	 *       }
1062*00808be7SEduard Zingerman 	 *     }
1063*00808be7SEduard Zingerman 	 *     iter_destroy(i);
1064*00808be7SEduard Zingerman 	 *   }
1065*00808be7SEduard Zingerman 	 *   iter_destroy(j);
1066*00808be7SEduard Zingerman 	 *   return;
1067*00808be7SEduard Zingerman 	 */
1068*00808be7SEduard Zingerman 	asm volatile (
1069*00808be7SEduard Zingerman 		"r1 = r10;"
1070*00808be7SEduard Zingerman 		"r1 += -16;"
1071*00808be7SEduard Zingerman 		"r2 = 0;"
1072*00808be7SEduard Zingerman 		"r3 = 10;"
1073*00808be7SEduard Zingerman 		"call %[bpf_iter_num_new];"
1074*00808be7SEduard Zingerman 		"r6 = 0;"
1075*00808be7SEduard Zingerman 		"r7 = 0;"
1076*00808be7SEduard Zingerman 		"r8 = -24;"
1077*00808be7SEduard Zingerman 	"j_loop_%=:"
1078*00808be7SEduard Zingerman 		"r1 = r10;"
1079*00808be7SEduard Zingerman 		"r1 += -16;"
1080*00808be7SEduard Zingerman 		"call %[bpf_iter_num_next];"
1081*00808be7SEduard Zingerman 		"if r0 == 0 goto j_loop_end_%=;"
1082*00808be7SEduard Zingerman 
1083*00808be7SEduard Zingerman 		/* first inner loop */
1084*00808be7SEduard Zingerman 		"r1 = r10;"
1085*00808be7SEduard Zingerman 		"r1 += -8;"
1086*00808be7SEduard Zingerman 		"r2 = 0;"
1087*00808be7SEduard Zingerman 		"r3 = 10;"
1088*00808be7SEduard Zingerman 		"call %[bpf_iter_num_new];"
1089*00808be7SEduard Zingerman 		"r6 = 0;"
1090*00808be7SEduard Zingerman 		"r7 = 0;"
1091*00808be7SEduard Zingerman 	"i_loop_%=:"
1092*00808be7SEduard Zingerman 		"r1 = r10;"
1093*00808be7SEduard Zingerman 		"r1 += -8;"
1094*00808be7SEduard Zingerman 		"call %[bpf_iter_num_next];"
1095*00808be7SEduard Zingerman 		"if r0 == 0 goto i_loop_end_%=;"
1096*00808be7SEduard Zingerman 	"check_one_r6_%=:"
1097*00808be7SEduard Zingerman 		"if r6 != 1 goto check_zero_r6_%=;"
1098*00808be7SEduard Zingerman 		"r6 = 0;"
1099*00808be7SEduard Zingerman 		"r7 = 1;"
1100*00808be7SEduard Zingerman 		"goto i_loop_%=;"
1101*00808be7SEduard Zingerman 	"check_zero_r6_%=:"
1102*00808be7SEduard Zingerman 		"if r6 != 0 goto i_loop_%=;"
1103*00808be7SEduard Zingerman 		"r6 = 1;"
1104*00808be7SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
1105*00808be7SEduard Zingerman 		"if r0 != 42 goto check_one_r7_%=;"
1106*00808be7SEduard Zingerman 		"goto i_loop_%=;"
1107*00808be7SEduard Zingerman 	"check_one_r7_%=:"
1108*00808be7SEduard Zingerman 		"if r7 != 1 goto i_loop_%=;"
1109*00808be7SEduard Zingerman 		"r0 = r10;"
1110*00808be7SEduard Zingerman 		"r0 += r8;"
1111*00808be7SEduard Zingerman 		"r1 = 7;"
1112*00808be7SEduard Zingerman 		"*(u64 *)(r0 + 0) = r1;"
1113*00808be7SEduard Zingerman 		"r1 = r10;"
1114*00808be7SEduard Zingerman 		"r1 += -8;"
1115*00808be7SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
1116*00808be7SEduard Zingerman 		"r1 = r10;"
1117*00808be7SEduard Zingerman 		"r1 += -16;"
1118*00808be7SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
1119*00808be7SEduard Zingerman 		"r0 = 0;"
1120*00808be7SEduard Zingerman 		"exit;"
1121*00808be7SEduard Zingerman 	"i_loop_end_%=:"
1122*00808be7SEduard Zingerman 		"r1 = r10;"
1123*00808be7SEduard Zingerman 		"r1 += -8;"
1124*00808be7SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
1125*00808be7SEduard Zingerman 
1126*00808be7SEduard Zingerman 		/* second inner loop */
1127*00808be7SEduard Zingerman 		"r1 = r10;"
1128*00808be7SEduard Zingerman 		"r1 += -8;"
1129*00808be7SEduard Zingerman 		"r2 = 0;"
1130*00808be7SEduard Zingerman 		"r3 = 10;"
1131*00808be7SEduard Zingerman 		"call %[bpf_iter_num_new];"
1132*00808be7SEduard Zingerman 		"r6 = 0;"
1133*00808be7SEduard Zingerman 		"r7 = 0;"
1134*00808be7SEduard Zingerman 	"i2_loop_%=:"
1135*00808be7SEduard Zingerman 		"r1 = r10;"
1136*00808be7SEduard Zingerman 		"r1 += -8;"
1137*00808be7SEduard Zingerman 		"call %[bpf_iter_num_next];"
1138*00808be7SEduard Zingerman 		"if r0 == 0 goto i2_loop_end_%=;"
1139*00808be7SEduard Zingerman 	"check2_one_r6_%=:"
1140*00808be7SEduard Zingerman 		"if r6 != 1 goto check2_zero_r6_%=;"
1141*00808be7SEduard Zingerman 		"r6 = 0;"
1142*00808be7SEduard Zingerman 		"r7 = 1;"
1143*00808be7SEduard Zingerman 		"goto i2_loop_%=;"
1144*00808be7SEduard Zingerman 	"check2_zero_r6_%=:"
1145*00808be7SEduard Zingerman 		"if r6 != 0 goto i2_loop_%=;"
1146*00808be7SEduard Zingerman 		"r6 = 1;"
1147*00808be7SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
1148*00808be7SEduard Zingerman 		"if r0 != 42 goto check2_one_r7_%=;"
1149*00808be7SEduard Zingerman 		"goto i2_loop_%=;"
1150*00808be7SEduard Zingerman 	"check2_one_r7_%=:"
1151*00808be7SEduard Zingerman 		"if r7 != 1 goto i2_loop_%=;"
1152*00808be7SEduard Zingerman 		"r6 = 0;"
1153*00808be7SEduard Zingerman 		"r8 = -25;"
1154*00808be7SEduard Zingerman 		"goto i2_loop_%=;"
1155*00808be7SEduard Zingerman 	"i2_loop_end_%=:"
1156*00808be7SEduard Zingerman 		"r1 = r10;"
1157*00808be7SEduard Zingerman 		"r1 += -8;"
1158*00808be7SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
1159*00808be7SEduard Zingerman 
1160*00808be7SEduard Zingerman 		"r6 = 0;"
1161*00808be7SEduard Zingerman 		"r7 = 0;"
1162*00808be7SEduard Zingerman 		"goto j_loop_%=;"
1163*00808be7SEduard Zingerman 	"j_loop_end_%=:"
1164*00808be7SEduard Zingerman 		"r1 = r10;"
1165*00808be7SEduard Zingerman 		"r1 += -16;"
1166*00808be7SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
1167*00808be7SEduard Zingerman 		"r0 = 0;"
1168*00808be7SEduard Zingerman 		"exit;"
1169*00808be7SEduard Zingerman 		:
1170*00808be7SEduard Zingerman 		: __imm(bpf_get_prandom_u32),
1171*00808be7SEduard Zingerman 		  __imm(bpf_iter_num_new),
1172*00808be7SEduard Zingerman 		  __imm(bpf_iter_num_next),
1173*00808be7SEduard Zingerman 		  __imm(bpf_iter_num_destroy)
1174*00808be7SEduard Zingerman 		: __clobber_all
1175*00808be7SEduard Zingerman 	);
1176*00808be7SEduard Zingerman }
1177*00808be7SEduard Zingerman 
1178*00808be7SEduard Zingerman SEC("?raw_tp")
11797f764ea0SEduard Zingerman __success
triple_continue(void)11807f764ea0SEduard Zingerman __naked int triple_continue(void)
11817f764ea0SEduard Zingerman {
11827f764ea0SEduard Zingerman 	/* This is equivalent to C program below.
11837f764ea0SEduard Zingerman 	 * High branching factor of the loop body turned out to be
11847f764ea0SEduard Zingerman 	 * problematic for one of the iterator convergence tracking
11857f764ea0SEduard Zingerman 	 * algorithms explored.
11867f764ea0SEduard Zingerman 	 *
11877f764ea0SEduard Zingerman 	 * r6 = bpf_get_prandom_u32()
11887f764ea0SEduard Zingerman 	 * bpf_iter_num_new(&fp[-8], 0, 10)
11897f764ea0SEduard Zingerman 	 * while (bpf_iter_num_next(&fp[-8])) {
11907f764ea0SEduard Zingerman 	 *   if (bpf_get_prandom_u32() != 42)
11917f764ea0SEduard Zingerman 	 *     continue;
11927f764ea0SEduard Zingerman 	 *   if (bpf_get_prandom_u32() != 42)
11937f764ea0SEduard Zingerman 	 *     continue;
11947f764ea0SEduard Zingerman 	 *   if (bpf_get_prandom_u32() != 42)
11957f764ea0SEduard Zingerman 	 *     continue;
11967f764ea0SEduard Zingerman 	 *   r0 += 0;
11977f764ea0SEduard Zingerman 	 * }
11987f764ea0SEduard Zingerman 	 * bpf_iter_num_destroy(&fp[-8])
11997f764ea0SEduard Zingerman 	 * return 0
12007f764ea0SEduard Zingerman 	 */
12017f764ea0SEduard Zingerman 	asm volatile (
12027f764ea0SEduard Zingerman 		"r1 = r10;"
12037f764ea0SEduard Zingerman 		"r1 += -8;"
12047f764ea0SEduard Zingerman 		"r2 = 0;"
12057f764ea0SEduard Zingerman 		"r3 = 10;"
12067f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
12077f764ea0SEduard Zingerman 	"loop_%=:"
12087f764ea0SEduard Zingerman 		"r1 = r10;"
12097f764ea0SEduard Zingerman 		"r1 += -8;"
12107f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
12117f764ea0SEduard Zingerman 		"if r0 == 0 goto loop_end_%=;"
12127f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
12137f764ea0SEduard Zingerman 		"if r0 != 42 goto loop_%=;"
12147f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
12157f764ea0SEduard Zingerman 		"if r0 != 42 goto loop_%=;"
12167f764ea0SEduard Zingerman 		"call %[bpf_get_prandom_u32];"
12177f764ea0SEduard Zingerman 		"if r0 != 42 goto loop_%=;"
12187f764ea0SEduard Zingerman 		"r0 += 0;"
12197f764ea0SEduard Zingerman 		"goto loop_%=;"
12207f764ea0SEduard Zingerman 	"loop_end_%=:"
12217f764ea0SEduard Zingerman 		"r1 = r10;"
12227f764ea0SEduard Zingerman 		"r1 += -8;"
12237f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
12247f764ea0SEduard Zingerman 		"r0 = 0;"
12257f764ea0SEduard Zingerman 		"exit;"
12267f764ea0SEduard Zingerman 		:
12277f764ea0SEduard Zingerman 		: __imm(bpf_get_prandom_u32),
12287f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_new),
12297f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_next),
12307f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_destroy)
12317f764ea0SEduard Zingerman 		: __clobber_all
12327f764ea0SEduard Zingerman 	);
12337f764ea0SEduard Zingerman }
12347f764ea0SEduard Zingerman 
12357f764ea0SEduard Zingerman SEC("?raw_tp")
12367f764ea0SEduard Zingerman __success
widen_spill(void)12377f764ea0SEduard Zingerman __naked int widen_spill(void)
12387f764ea0SEduard Zingerman {
12397f764ea0SEduard Zingerman 	/* This is equivalent to C program below.
12407f764ea0SEduard Zingerman 	 * The counter is stored in fp[-16], if this counter is not widened
12417f764ea0SEduard Zingerman 	 * verifier states representing loop iterations would never converge.
12427f764ea0SEduard Zingerman 	 *
12437f764ea0SEduard Zingerman 	 * fp[-16] = 0
12447f764ea0SEduard Zingerman 	 * bpf_iter_num_new(&fp[-8], 0, 10)
12457f764ea0SEduard Zingerman 	 * while (bpf_iter_num_next(&fp[-8])) {
12467f764ea0SEduard Zingerman 	 *   r0 = fp[-16];
12477f764ea0SEduard Zingerman 	 *   r0 += 1;
12487f764ea0SEduard Zingerman 	 *   fp[-16] = r0;
12497f764ea0SEduard Zingerman 	 * }
12507f764ea0SEduard Zingerman 	 * bpf_iter_num_destroy(&fp[-8])
12517f764ea0SEduard Zingerman 	 * return 0
12527f764ea0SEduard Zingerman 	 */
12537f764ea0SEduard Zingerman 	asm volatile (
12547f764ea0SEduard Zingerman 		"r0 = 0;"
12557f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 16) = r0;"
12567f764ea0SEduard Zingerman 		"r1 = r10;"
12577f764ea0SEduard Zingerman 		"r1 += -8;"
12587f764ea0SEduard Zingerman 		"r2 = 0;"
12597f764ea0SEduard Zingerman 		"r3 = 10;"
12607f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
12617f764ea0SEduard Zingerman 	"loop_%=:"
12627f764ea0SEduard Zingerman 		"r1 = r10;"
12637f764ea0SEduard Zingerman 		"r1 += -8;"
12647f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
12657f764ea0SEduard Zingerman 		"if r0 == 0 goto loop_end_%=;"
12667f764ea0SEduard Zingerman 		"r0 = *(u64 *)(r10 - 16);"
12677f764ea0SEduard Zingerman 		"r0 += 1;"
12687f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 16) = r0;"
12697f764ea0SEduard Zingerman 		"goto loop_%=;"
12707f764ea0SEduard Zingerman 	"loop_end_%=:"
12717f764ea0SEduard Zingerman 		"r1 = r10;"
12727f764ea0SEduard Zingerman 		"r1 += -8;"
12737f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
12747f764ea0SEduard Zingerman 		"r0 = 0;"
12757f764ea0SEduard Zingerman 		"exit;"
12767f764ea0SEduard Zingerman 		:
12777f764ea0SEduard Zingerman 		: __imm(bpf_iter_num_new),
12787f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_next),
12797f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_destroy)
12807f764ea0SEduard Zingerman 		: __clobber_all
12817f764ea0SEduard Zingerman 	);
12827f764ea0SEduard Zingerman }
12837f764ea0SEduard Zingerman 
12847f764ea0SEduard Zingerman SEC("raw_tp")
12857f764ea0SEduard Zingerman __success
checkpoint_states_deletion(void)12867f764ea0SEduard Zingerman __naked int checkpoint_states_deletion(void)
12877f764ea0SEduard Zingerman {
12887f764ea0SEduard Zingerman 	/* This is equivalent to C program below.
12897f764ea0SEduard Zingerman 	 *
12907f764ea0SEduard Zingerman 	 *   int *a, *b, *c, *d, *e, *f;
12917f764ea0SEduard Zingerman 	 *   int i, sum = 0;
12927f764ea0SEduard Zingerman 	 *   bpf_for(i, 0, 10) {
12937f764ea0SEduard Zingerman 	 *     a = bpf_map_lookup_elem(&amap, &i);
12947f764ea0SEduard Zingerman 	 *     b = bpf_map_lookup_elem(&amap, &i);
12957f764ea0SEduard Zingerman 	 *     c = bpf_map_lookup_elem(&amap, &i);
12967f764ea0SEduard Zingerman 	 *     d = bpf_map_lookup_elem(&amap, &i);
12977f764ea0SEduard Zingerman 	 *     e = bpf_map_lookup_elem(&amap, &i);
12987f764ea0SEduard Zingerman 	 *     f = bpf_map_lookup_elem(&amap, &i);
12997f764ea0SEduard Zingerman 	 *     if (a) sum += 1;
13007f764ea0SEduard Zingerman 	 *     if (b) sum += 1;
13017f764ea0SEduard Zingerman 	 *     if (c) sum += 1;
13027f764ea0SEduard Zingerman 	 *     if (d) sum += 1;
13037f764ea0SEduard Zingerman 	 *     if (e) sum += 1;
13047f764ea0SEduard Zingerman 	 *     if (f) sum += 1;
13057f764ea0SEduard Zingerman 	 *   }
13067f764ea0SEduard Zingerman 	 *   return 0;
13077f764ea0SEduard Zingerman 	 *
13087f764ea0SEduard Zingerman 	 * The body of the loop spawns multiple simulation paths
13097f764ea0SEduard Zingerman 	 * with different combination of NULL/non-NULL information for a/b/c/d/e/f.
13107f764ea0SEduard Zingerman 	 * Each combination is unique from states_equal() point of view.
13117f764ea0SEduard Zingerman 	 * Explored states checkpoint is created after each iterator next call.
13127f764ea0SEduard Zingerman 	 * Iterator convergence logic expects that eventually current state
13137f764ea0SEduard Zingerman 	 * would get equal to one of the explored states and thus loop
13147f764ea0SEduard Zingerman 	 * exploration would be finished (at-least for a specific path).
13157f764ea0SEduard Zingerman 	 * Verifier evicts explored states with high miss to hit ratio
13167f764ea0SEduard Zingerman 	 * to to avoid comparing current state with too many explored
13177f764ea0SEduard Zingerman 	 * states per instruction.
13187f764ea0SEduard Zingerman 	 * This test is designed to "stress test" eviction policy defined using formula:
13197f764ea0SEduard Zingerman 	 *
13207f764ea0SEduard Zingerman 	 *    sl->miss_cnt > sl->hit_cnt * N + N // if true sl->state is evicted
13217f764ea0SEduard Zingerman 	 *
13227f764ea0SEduard Zingerman 	 * Currently N is set to 64, which allows for 6 variables in this test.
13237f764ea0SEduard Zingerman 	 */
13247f764ea0SEduard Zingerman 	asm volatile (
13257f764ea0SEduard Zingerman 		"r6 = 0;"                  /* a */
13267f764ea0SEduard Zingerman 		"r7 = 0;"                  /* b */
13277f764ea0SEduard Zingerman 		"r8 = 0;"                  /* c */
13287f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 24) = r6;" /* d */
13297f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 32) = r6;" /* e */
13307f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 40) = r6;" /* f */
13317f764ea0SEduard Zingerman 		"r9 = 0;"                  /* sum */
13327f764ea0SEduard Zingerman 		"r1 = r10;"
13337f764ea0SEduard Zingerman 		"r1 += -8;"
13347f764ea0SEduard Zingerman 		"r2 = 0;"
13357f764ea0SEduard Zingerman 		"r3 = 10;"
13367f764ea0SEduard Zingerman 		"call %[bpf_iter_num_new];"
13377f764ea0SEduard Zingerman 	"loop_%=:"
13387f764ea0SEduard Zingerman 		"r1 = r10;"
13397f764ea0SEduard Zingerman 		"r1 += -8;"
13407f764ea0SEduard Zingerman 		"call %[bpf_iter_num_next];"
13417f764ea0SEduard Zingerman 		"if r0 == 0 goto loop_end_%=;"
13427f764ea0SEduard Zingerman 
13437f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 16) = r0;"
13447f764ea0SEduard Zingerman 
13457f764ea0SEduard Zingerman 		"r1 = %[amap] ll;"
13467f764ea0SEduard Zingerman 		"r2 = r10;"
13477f764ea0SEduard Zingerman 		"r2 += -16;"
13487f764ea0SEduard Zingerman 		"call %[bpf_map_lookup_elem];"
13497f764ea0SEduard Zingerman 		"r6 = r0;"
13507f764ea0SEduard Zingerman 
13517f764ea0SEduard Zingerman 		"r1 = %[amap] ll;"
13527f764ea0SEduard Zingerman 		"r2 = r10;"
13537f764ea0SEduard Zingerman 		"r2 += -16;"
13547f764ea0SEduard Zingerman 		"call %[bpf_map_lookup_elem];"
13557f764ea0SEduard Zingerman 		"r7 = r0;"
13567f764ea0SEduard Zingerman 
13577f764ea0SEduard Zingerman 		"r1 = %[amap] ll;"
13587f764ea0SEduard Zingerman 		"r2 = r10;"
13597f764ea0SEduard Zingerman 		"r2 += -16;"
13607f764ea0SEduard Zingerman 		"call %[bpf_map_lookup_elem];"
13617f764ea0SEduard Zingerman 		"r8 = r0;"
13627f764ea0SEduard Zingerman 
13637f764ea0SEduard Zingerman 		"r1 = %[amap] ll;"
13647f764ea0SEduard Zingerman 		"r2 = r10;"
13657f764ea0SEduard Zingerman 		"r2 += -16;"
13667f764ea0SEduard Zingerman 		"call %[bpf_map_lookup_elem];"
13677f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 24) = r0;"
13687f764ea0SEduard Zingerman 
13697f764ea0SEduard Zingerman 		"r1 = %[amap] ll;"
13707f764ea0SEduard Zingerman 		"r2 = r10;"
13717f764ea0SEduard Zingerman 		"r2 += -16;"
13727f764ea0SEduard Zingerman 		"call %[bpf_map_lookup_elem];"
13737f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 32) = r0;"
13747f764ea0SEduard Zingerman 
13757f764ea0SEduard Zingerman 		"r1 = %[amap] ll;"
13767f764ea0SEduard Zingerman 		"r2 = r10;"
13777f764ea0SEduard Zingerman 		"r2 += -16;"
13787f764ea0SEduard Zingerman 		"call %[bpf_map_lookup_elem];"
13797f764ea0SEduard Zingerman 		"*(u64 *)(r10 - 40) = r0;"
13807f764ea0SEduard Zingerman 
13817f764ea0SEduard Zingerman 		"if r6 == 0 goto +1;"
13827f764ea0SEduard Zingerman 		"r9 += 1;"
13837f764ea0SEduard Zingerman 		"if r7 == 0 goto +1;"
13847f764ea0SEduard Zingerman 		"r9 += 1;"
13857f764ea0SEduard Zingerman 		"if r8 == 0 goto +1;"
13867f764ea0SEduard Zingerman 		"r9 += 1;"
13877f764ea0SEduard Zingerman 		"r0 = *(u64 *)(r10 - 24);"
13887f764ea0SEduard Zingerman 		"if r0 == 0 goto +1;"
13897f764ea0SEduard Zingerman 		"r9 += 1;"
13907f764ea0SEduard Zingerman 		"r0 = *(u64 *)(r10 - 32);"
13917f764ea0SEduard Zingerman 		"if r0 == 0 goto +1;"
13927f764ea0SEduard Zingerman 		"r9 += 1;"
13937f764ea0SEduard Zingerman 		"r0 = *(u64 *)(r10 - 40);"
13947f764ea0SEduard Zingerman 		"if r0 == 0 goto +1;"
13957f764ea0SEduard Zingerman 		"r9 += 1;"
13967f764ea0SEduard Zingerman 
13977f764ea0SEduard Zingerman 		"goto loop_%=;"
13987f764ea0SEduard Zingerman 	"loop_end_%=:"
13997f764ea0SEduard Zingerman 		"r1 = r10;"
14007f764ea0SEduard Zingerman 		"r1 += -8;"
14017f764ea0SEduard Zingerman 		"call %[bpf_iter_num_destroy];"
14027f764ea0SEduard Zingerman 		"r0 = 0;"
14037f764ea0SEduard Zingerman 		"exit;"
14047f764ea0SEduard Zingerman 		:
14057f764ea0SEduard Zingerman 		: __imm(bpf_map_lookup_elem),
14067f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_new),
14077f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_next),
14087f764ea0SEduard Zingerman 		  __imm(bpf_iter_num_destroy),
14097f764ea0SEduard Zingerman 		  __imm_addr(amap)
14107f764ea0SEduard Zingerman 		: __clobber_all
14117f764ea0SEduard Zingerman 	);
14127f764ea0SEduard Zingerman }
14137f764ea0SEduard Zingerman 
141457400dccSAndrii Nakryiko char _license[] SEC("license") = "GPL";
1415