1226048Sobrien// SPDX-License-Identifier: GPL-2.0
268349Sobrien/* Converted from tools/testing/selftests/bpf/verifier/bpf_get_stack.c */
3284778Sdelphij
468349Sobrien#include <linux/bpf.h>
568349Sobrien#include <bpf/bpf_helpers.h>
668349Sobrien#include "bpf_misc.h"
768349Sobrien
868349Sobrien#define MAX_ENTRIES 11
968349Sobrien
1068349Sobrienstruct test_val {
11284778Sdelphij	unsigned int index;
1268349Sobrien	int foo[MAX_ENTRIES];
13284778Sdelphij};
1468349Sobrien
1568349Sobrienstruct {
1668349Sobrien	__uint(type, BPF_MAP_TYPE_ARRAY);
1768349Sobrien	__uint(max_entries, 1);
1868349Sobrien	__type(key, int);
1968349Sobrien	__type(value, struct test_val);
20284778Sdelphij} map_array_48b SEC(".maps");
2168349Sobrien
2268349Sobrienstruct {
2368349Sobrien	__uint(type, BPF_MAP_TYPE_HASH);
2468349Sobrien	__uint(max_entries, 1);
2568349Sobrien	__type(key, long long);
2668349Sobrien	__type(value, struct test_val);
2768349Sobrien} map_hash_48b SEC(".maps");
2868349Sobrien
2968349SobrienSEC("tracepoint")
3068349Sobrien__description("bpf_get_stack return R0 within range")
31284778Sdelphij__success
32169962Sobrien__naked void stack_return_r0_within_range(void)
33284778Sdelphij{
3468349Sobrien	asm volatile ("					\
35284778Sdelphij	r6 = r1;					\
3668349Sobrien	r1 = 0;						\
37284778Sdelphij	*(u64*)(r10 - 8) = r1;				\
3868349Sobrien	r2 = r10;					\
39284778Sdelphij	r2 += -8;					\
4068349Sobrien	r1 = %[map_hash_48b] ll;			\
41284778Sdelphij	call %[bpf_map_lookup_elem];			\
4268349Sobrien	if r0 == 0 goto l0_%=;				\
43284778Sdelphij	r7 = r0;					\
4468349Sobrien	r9 = %[__imm_0];				\
45284778Sdelphij	r1 = r6;					\
4668349Sobrien	r2 = r7;					\
4768349Sobrien	r3 = %[__imm_0];				\
4868349Sobrien	r4 = 256;					\
4968349Sobrien	call %[bpf_get_stack];				\
5068349Sobrien	r1 = 0;						\
5168349Sobrien	r8 = r0;					\
5268349Sobrien	r8 <<= 32;					\
5368349Sobrien	r8 s>>= 32;					\
5468349Sobrien	if r1 s> r8 goto l0_%=;				\
5568349Sobrien	r9 -= r8;					\
5668349Sobrien	r2 = r7;					\
5768349Sobrien	r2 += r8;					\
5868349Sobrien	r1 = r9;					\
5968349Sobrien	r1 <<= 32;					\
6068349Sobrien	r1 s>>= 32;					\
6168349Sobrien	r3 = r2;					\
6268349Sobrien	r3 += r1;					\
6368349Sobrien	r1 = r7;					\
6468349Sobrien	r5 = %[__imm_0];				\
6568349Sobrien	r1 += r5;					\
6668349Sobrien	if r3 >= r1 goto l0_%=;				\
6768349Sobrien	r1 = r6;					\
6868349Sobrien	r3 = r9;					\
6968349Sobrien	r4 = 0;						\
7068349Sobrien	call %[bpf_get_stack];				\
71186690Sobrienl0_%=:	exit;						\
72186690Sobrien"	:
73133359Sobrien	: __imm(bpf_get_stack),
74133359Sobrien	  __imm(bpf_map_lookup_elem),
75133359Sobrien	  __imm_addr(map_hash_48b),
76133359Sobrien	  __imm_const(__imm_0, sizeof(struct test_val) / 2)
77133359Sobrien	: __clobber_all);
78133359Sobrien}
79133359Sobrien
80133359SobrienSEC("iter/task")
81133359Sobrien__description("bpf_get_task_stack return R0 range is refined")
82__success
83__naked void return_r0_range_is_refined(void)
84{
85	asm volatile ("					\
86	r6 = *(u64*)(r1 + 0);				\
87	r6 = *(u64*)(r6 + 0);		/* ctx->meta->seq */\
88	r7 = *(u64*)(r1 + 8);		/* ctx->task */\
89	r1 = %[map_array_48b] ll;	/* fixup_map_array_48b */\
90	r2 = 0;						\
91	*(u64*)(r10 - 8) = r2;				\
92	r2 = r10;					\
93	r2 += -8;					\
94	call %[bpf_map_lookup_elem];			\
95	if r0 != 0 goto l0_%=;				\
96	r0 = 0;						\
97	exit;						\
98l0_%=:	if r7 != 0 goto l1_%=;				\
99	r0 = 0;						\
100	exit;						\
101l1_%=:	r1 = r7;					\
102	r2 = r0;					\
103	r9 = r0;			/* keep buf for seq_write */\
104	r3 = 48;					\
105	r4 = 0;						\
106	call %[bpf_get_task_stack];			\
107	if r0 s> 0 goto l2_%=;				\
108	r0 = 0;						\
109	exit;						\
110l2_%=:	r1 = r6;					\
111	r2 = r9;					\
112	r3 = r0;					\
113	call %[bpf_seq_write];				\
114	r0 = 0;						\
115	exit;						\
116"	:
117	: __imm(bpf_get_task_stack),
118	  __imm(bpf_map_lookup_elem),
119	  __imm(bpf_seq_write),
120	  __imm_addr(map_array_48b)
121	: __clobber_all);
122}
123
124char _license[] SEC("license") = "GPL";
125