1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (c) 2023 Meta Platforms, Inc. and affiliates. */
3
4 #include <errno.h>
5 #include <string.h>
6 #include <linux/bpf.h>
7 #include <bpf/bpf_helpers.h>
8 #include "bpf_misc.h"
9
10 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
11
12 int vals[] SEC(".data.vals") = {1, 2, 3, 4};
13
14 __naked __noinline __used
identity_subprog()15 static unsigned long identity_subprog()
16 {
17 /* the simplest *static* 64-bit identity function */
18 asm volatile (
19 "r0 = r1;"
20 "exit;"
21 );
22 }
23
24 __noinline __used
global_identity_subprog(__u64 x)25 unsigned long global_identity_subprog(__u64 x)
26 {
27 /* the simplest *global* 64-bit identity function */
28 return x;
29 }
30
31 __naked __noinline __used
callback_subprog()32 static unsigned long callback_subprog()
33 {
34 /* the simplest callback function */
35 asm volatile (
36 "r0 = 0;"
37 "exit;"
38 );
39 }
40
41 SEC("?raw_tp")
42 __success __log_level(2)
43 __msg("7: (0f) r1 += r0")
44 __msg("mark_precise: frame0: regs=r0 stack= before 6: (bf) r1 = r7")
45 __msg("mark_precise: frame0: regs=r0 stack= before 5: (27) r0 *= 4")
46 __msg("mark_precise: frame0: regs=r0 stack= before 11: (95) exit")
47 __msg("mark_precise: frame1: regs=r0 stack= before 10: (bf) r0 = r1")
48 __msg("mark_precise: frame1: regs=r1 stack= before 4: (85) call pc+5")
49 __msg("mark_precise: frame0: regs=r1 stack= before 3: (bf) r1 = r6")
50 __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
subprog_result_precise(void)51 __naked int subprog_result_precise(void)
52 {
53 asm volatile (
54 "r6 = 3;"
55 /* pass r6 through r1 into subprog to get it back as r0;
56 * this whole chain will have to be marked as precise later
57 */
58 "r1 = r6;"
59 "call identity_subprog;"
60 /* now use subprog's returned value (which is a
61 * r6 -> r1 -> r0 chain), as index into vals array, forcing
62 * all of that to be known precisely
63 */
64 "r0 *= 4;"
65 "r1 = %[vals];"
66 /* here r0->r1->r6 chain is forced to be precise and has to be
67 * propagated back to the beginning, including through the
68 * subprog call
69 */
70 "r1 += r0;"
71 "r0 = *(u32 *)(r1 + 0);"
72 "exit;"
73 :
74 : __imm_ptr(vals)
75 : __clobber_common, "r6"
76 );
77 }
78
79 SEC("?raw_tp")
80 __success __log_level(2)
81 __msg("9: (0f) r1 += r0")
82 __msg("mark_precise: frame0: last_idx 9 first_idx 0")
83 __msg("mark_precise: frame0: regs=r0 stack= before 8: (bf) r1 = r7")
84 __msg("mark_precise: frame0: regs=r0 stack= before 7: (27) r0 *= 4")
85 __msg("mark_precise: frame0: regs=r0 stack= before 5: (a5) if r0 < 0x4 goto pc+1")
86 __msg("mark_precise: frame0: regs=r0 stack= before 4: (85) call pc+7")
global_subprog_result_precise(void)87 __naked int global_subprog_result_precise(void)
88 {
89 asm volatile (
90 "r6 = 3;"
91 /* pass r6 through r1 into subprog to get it back as r0;
92 * given global_identity_subprog is global, precision won't
93 * propagate all the way back to r6
94 */
95 "r1 = r6;"
96 "call global_identity_subprog;"
97 /* now use subprog's returned value (which is unknown now, so
98 * we need to clamp it), as index into vals array, forcing r0
99 * to be marked precise (with no effect on r6, though)
100 */
101 "if r0 < %[vals_arr_sz] goto 1f;"
102 "r0 = %[vals_arr_sz] - 1;"
103 "1:"
104 "r0 *= 4;"
105 "r1 = %[vals];"
106 /* here r0 is forced to be precise and has to be
107 * propagated back to the global subprog call, but it
108 * shouldn't go all the way to mark r6 as precise
109 */
110 "r1 += r0;"
111 "r0 = *(u32 *)(r1 + 0);"
112 "exit;"
113 :
114 : __imm_ptr(vals),
115 __imm_const(vals_arr_sz, ARRAY_SIZE(vals))
116 : __clobber_common, "r6"
117 );
118 }
119
120 SEC("?raw_tp")
121 __success __log_level(2)
122 /* First simulated path does not include callback body,
123 * r1 and r4 are always precise for bpf_loop() calls.
124 */
125 __msg("9: (85) call bpf_loop#181")
126 __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
127 __msg("mark_precise: frame0: parent state regs=r4 stack=:")
128 __msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9")
129 __msg("mark_precise: frame0: regs=r4 stack= before 8: (b7) r4 = 0")
130 __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
131 __msg("mark_precise: frame0: parent state regs=r1 stack=:")
132 __msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9")
133 __msg("mark_precise: frame0: regs=r1 stack= before 8: (b7) r4 = 0")
134 __msg("mark_precise: frame0: regs=r1 stack= before 7: (b7) r3 = 0")
135 __msg("mark_precise: frame0: regs=r1 stack= before 6: (bf) r2 = r8")
136 __msg("mark_precise: frame0: regs=r1 stack= before 5: (bf) r1 = r6")
137 __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3")
138 /* r6 precision propagation */
139 __msg("14: (0f) r1 += r6")
140 __msg("mark_precise: frame0: last_idx 14 first_idx 9")
141 __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7")
142 __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4")
143 __msg("mark_precise: frame0: regs=r6 stack= before 11: (25) if r6 > 0x3 goto pc+4")
144 __msg("mark_precise: frame0: regs=r6 stack= before 10: (bf) r6 = r0")
145 __msg("mark_precise: frame0: regs=r0 stack= before 9: (85) call bpf_loop")
146 /* State entering callback body popped from states stack */
147 __msg("from 9 to 17: frame1:")
148 __msg("17: frame1: R1=scalar() R2=0 R10=fp0 cb")
149 __msg("17: (b7) r0 = 0")
150 __msg("18: (95) exit")
151 __msg("returning from callee:")
152 __msg("to caller at 9:")
153 __msg("frame 0: propagating r1,r4")
154 __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
155 __msg("mark_precise: frame0: regs=r1,r4 stack= before 18: (95) exit")
156 __msg("from 18 to 9: safe")
callback_result_precise(void)157 __naked int callback_result_precise(void)
158 {
159 asm volatile (
160 "r6 = 3;"
161
162 /* call subprog and use result; r0 shouldn't propagate back to
163 * callback_subprog
164 */
165 "r1 = r6;" /* nr_loops */
166 "r2 = %[callback_subprog];" /* callback_fn */
167 "r3 = 0;" /* callback_ctx */
168 "r4 = 0;" /* flags */
169 "call %[bpf_loop];"
170
171 "r6 = r0;"
172 "if r6 > 3 goto 1f;"
173 "r6 *= 4;"
174 "r1 = %[vals];"
175 /* here r6 is forced to be precise and has to be propagated
176 * back to the bpf_loop() call, but not beyond
177 */
178 "r1 += r6;"
179 "r0 = *(u32 *)(r1 + 0);"
180 "1:"
181 "exit;"
182 :
183 : __imm_ptr(vals),
184 __imm_ptr(callback_subprog),
185 __imm(bpf_loop)
186 : __clobber_common, "r6"
187 );
188 }
189
190 SEC("?raw_tp")
191 __success __log_level(2)
192 __msg("7: (0f) r1 += r6")
193 __msg("mark_precise: frame0: last_idx 7 first_idx 0")
194 __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7")
195 __msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4")
196 __msg("mark_precise: frame0: regs=r6 stack= before 11: (95) exit")
197 __msg("mark_precise: frame1: regs= stack= before 10: (bf) r0 = r1")
198 __msg("mark_precise: frame1: regs= stack= before 4: (85) call pc+5")
199 __msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0")
200 __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_callee_saved_reg_precise(void)201 __naked int parent_callee_saved_reg_precise(void)
202 {
203 asm volatile (
204 "r6 = 3;"
205
206 /* call subprog and ignore result; we need this call only to
207 * complicate jump history
208 */
209 "r1 = 0;"
210 "call identity_subprog;"
211
212 "r6 *= 4;"
213 "r1 = %[vals];"
214 /* here r6 is forced to be precise and has to be propagated
215 * back to the beginning, handling (and ignoring) subprog call
216 */
217 "r1 += r6;"
218 "r0 = *(u32 *)(r1 + 0);"
219 "exit;"
220 :
221 : __imm_ptr(vals)
222 : __clobber_common, "r6"
223 );
224 }
225
226 SEC("?raw_tp")
227 __success __log_level(2)
228 __msg("7: (0f) r1 += r6")
229 __msg("mark_precise: frame0: last_idx 7 first_idx 0")
230 __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r1 = r7")
231 __msg("mark_precise: frame0: regs=r6 stack= before 5: (27) r6 *= 4")
232 __msg("mark_precise: frame0: regs=r6 stack= before 4: (85) call pc+5")
233 __msg("mark_precise: frame0: regs=r6 stack= before 3: (b7) r1 = 0")
234 __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_callee_saved_reg_precise_global(void)235 __naked int parent_callee_saved_reg_precise_global(void)
236 {
237 asm volatile (
238 "r6 = 3;"
239
240 /* call subprog and ignore result; we need this call only to
241 * complicate jump history
242 */
243 "r1 = 0;"
244 "call global_identity_subprog;"
245
246 "r6 *= 4;"
247 "r1 = %[vals];"
248 /* here r6 is forced to be precise and has to be propagated
249 * back to the beginning, handling (and ignoring) subprog call
250 */
251 "r1 += r6;"
252 "r0 = *(u32 *)(r1 + 0);"
253 "exit;"
254 :
255 : __imm_ptr(vals)
256 : __clobber_common, "r6"
257 );
258 }
259
260 SEC("?raw_tp")
261 __success __log_level(2)
262 /* First simulated path does not include callback body */
263 __msg("12: (0f) r1 += r6")
264 __msg("mark_precise: frame0: last_idx 12 first_idx 9")
265 __msg("mark_precise: frame0: regs=r6 stack= before 11: (bf) r1 = r7")
266 __msg("mark_precise: frame0: regs=r6 stack= before 10: (27) r6 *= 4")
267 __msg("mark_precise: frame0: regs=r6 stack= before 9: (85) call bpf_loop")
268 __msg("mark_precise: frame0: parent state regs=r6 stack=:")
269 __msg("mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx 9")
270 __msg("mark_precise: frame0: regs=r6 stack= before 8: (b7) r4 = 0")
271 __msg("mark_precise: frame0: regs=r6 stack= before 7: (b7) r3 = 0")
272 __msg("mark_precise: frame0: regs=r6 stack= before 6: (bf) r2 = r8")
273 __msg("mark_precise: frame0: regs=r6 stack= before 5: (b7) r1 = 1")
274 __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3")
275 /* State entering callback body popped from states stack */
276 __msg("from 9 to 15: frame1:")
277 __msg("15: frame1: R1=scalar() R2=0 R10=fp0 cb")
278 __msg("15: (b7) r0 = 0")
279 __msg("16: (95) exit")
280 __msg("returning from callee:")
281 __msg("to caller at 9:")
282 /* r1, r4 are always precise for bpf_loop(),
283 * r6 was marked before backtracking to callback body.
284 */
285 __msg("frame 0: propagating r1,r4,r6")
286 __msg("mark_precise: frame0: last_idx 9 first_idx 9 subseq_idx -1")
287 __msg("mark_precise: frame0: regs=r1,r4,r6 stack= before 16: (95) exit")
288 __msg("mark_precise: frame1: regs= stack= before 15: (b7) r0 = 0")
289 __msg("mark_precise: frame1: regs= stack= before 9: (85) call bpf_loop")
290 __msg("mark_precise: frame0: parent state regs= stack=:")
291 __msg("from 16 to 9: safe")
parent_callee_saved_reg_precise_with_callback(void)292 __naked int parent_callee_saved_reg_precise_with_callback(void)
293 {
294 asm volatile (
295 "r6 = 3;"
296
297 /* call subprog and ignore result; we need this call only to
298 * complicate jump history
299 */
300 "r1 = 1;" /* nr_loops */
301 "r2 = %[callback_subprog];" /* callback_fn */
302 "r3 = 0;" /* callback_ctx */
303 "r4 = 0;" /* flags */
304 "call %[bpf_loop];"
305
306 "r6 *= 4;"
307 "r1 = %[vals];"
308 /* here r6 is forced to be precise and has to be propagated
309 * back to the beginning, handling (and ignoring) callback call
310 */
311 "r1 += r6;"
312 "r0 = *(u32 *)(r1 + 0);"
313 "exit;"
314 :
315 : __imm_ptr(vals),
316 __imm_ptr(callback_subprog),
317 __imm(bpf_loop)
318 : __clobber_common, "r6"
319 );
320 }
321
322 SEC("?raw_tp")
323 __success __log_level(2)
324 __msg("9: (0f) r1 += r6")
325 __msg("mark_precise: frame0: last_idx 9 first_idx 6")
326 __msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7")
327 __msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4")
328 __msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)")
329 __msg("mark_precise: frame0: parent state regs= stack=-8:")
330 __msg("mark_precise: frame0: last_idx 13 first_idx 0")
331 __msg("mark_precise: frame0: regs= stack=-8 before 13: (95) exit")
332 __msg("mark_precise: frame1: regs= stack= before 12: (bf) r0 = r1")
333 __msg("mark_precise: frame1: regs= stack= before 5: (85) call pc+6")
334 __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0")
335 __msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6")
336 __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_stack_slot_precise(void)337 __naked int parent_stack_slot_precise(void)
338 {
339 asm volatile (
340 /* spill reg */
341 "r6 = 3;"
342 "*(u64 *)(r10 - 8) = r6;"
343
344 /* call subprog and ignore result; we need this call only to
345 * complicate jump history
346 */
347 "r1 = 0;"
348 "call identity_subprog;"
349
350 /* restore reg from stack; in this case we'll be carrying
351 * stack mask when going back into subprog through jump
352 * history
353 */
354 "r6 = *(u64 *)(r10 - 8);"
355
356 "r6 *= 4;"
357 "r1 = %[vals];"
358 /* here r6 is forced to be precise and has to be propagated
359 * back to the beginning, handling (and ignoring) subprog call
360 */
361 "r1 += r6;"
362 "r0 = *(u32 *)(r1 + 0);"
363 "exit;"
364 :
365 : __imm_ptr(vals)
366 : __clobber_common, "r6"
367 );
368 }
369
370 SEC("?raw_tp")
371 __success __log_level(2)
372 __msg("9: (0f) r1 += r6")
373 __msg("mark_precise: frame0: last_idx 9 first_idx 6")
374 __msg("mark_precise: frame0: regs=r6 stack= before 8: (bf) r1 = r7")
375 __msg("mark_precise: frame0: regs=r6 stack= before 7: (27) r6 *= 4")
376 __msg("mark_precise: frame0: regs=r6 stack= before 6: (79) r6 = *(u64 *)(r10 -8)")
377 __msg("mark_precise: frame0: parent state regs= stack=-8:")
378 __msg("mark_precise: frame0: last_idx 5 first_idx 0")
379 __msg("mark_precise: frame0: regs= stack=-8 before 5: (85) call pc+6")
380 __msg("mark_precise: frame0: regs= stack=-8 before 4: (b7) r1 = 0")
381 __msg("mark_precise: frame0: regs= stack=-8 before 3: (7b) *(u64 *)(r10 -8) = r6")
382 __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 3")
parent_stack_slot_precise_global(void)383 __naked int parent_stack_slot_precise_global(void)
384 {
385 asm volatile (
386 /* spill reg */
387 "r6 = 3;"
388 "*(u64 *)(r10 - 8) = r6;"
389
390 /* call subprog and ignore result; we need this call only to
391 * complicate jump history
392 */
393 "r1 = 0;"
394 "call global_identity_subprog;"
395
396 /* restore reg from stack; in this case we'll be carrying
397 * stack mask when going back into subprog through jump
398 * history
399 */
400 "r6 = *(u64 *)(r10 - 8);"
401
402 "r6 *= 4;"
403 "r1 = %[vals];"
404 /* here r6 is forced to be precise and has to be propagated
405 * back to the beginning, handling (and ignoring) subprog call
406 */
407 "r1 += r6;"
408 "r0 = *(u32 *)(r1 + 0);"
409 "exit;"
410 :
411 : __imm_ptr(vals)
412 : __clobber_common, "r6"
413 );
414 }
415
416 SEC("?raw_tp")
417 __success __log_level(2)
418 /* First simulated path does not include callback body */
419 __msg("14: (0f) r1 += r6")
420 __msg("mark_precise: frame0: last_idx 14 first_idx 10")
421 __msg("mark_precise: frame0: regs=r6 stack= before 13: (bf) r1 = r7")
422 __msg("mark_precise: frame0: regs=r6 stack= before 12: (27) r6 *= 4")
423 __msg("mark_precise: frame0: regs=r6 stack= before 11: (79) r6 = *(u64 *)(r10 -8)")
424 __msg("mark_precise: frame0: regs= stack=-8 before 10: (85) call bpf_loop")
425 __msg("mark_precise: frame0: parent state regs= stack=-8:")
426 __msg("mark_precise: frame0: last_idx 9 first_idx 0 subseq_idx 10")
427 __msg("mark_precise: frame0: regs= stack=-8 before 9: (b7) r4 = 0")
428 __msg("mark_precise: frame0: regs= stack=-8 before 8: (b7) r3 = 0")
429 __msg("mark_precise: frame0: regs= stack=-8 before 7: (bf) r2 = r8")
430 __msg("mark_precise: frame0: regs= stack=-8 before 6: (bf) r1 = r6")
431 __msg("mark_precise: frame0: regs= stack=-8 before 5: (7b) *(u64 *)(r10 -8) = r6")
432 __msg("mark_precise: frame0: regs=r6 stack= before 4: (b7) r6 = 3")
433 /* State entering callback body popped from states stack */
434 __msg("from 10 to 17: frame1:")
435 __msg("17: frame1: R1=scalar() R2=0 R10=fp0 cb")
436 __msg("17: (b7) r0 = 0")
437 __msg("18: (95) exit")
438 __msg("returning from callee:")
439 __msg("to caller at 10:")
440 /* r1, r4 are always precise for bpf_loop(),
441 * fp-8 was marked before backtracking to callback body.
442 */
443 __msg("frame 0: propagating r1,r4,fp-8")
444 __msg("mark_precise: frame0: last_idx 10 first_idx 10 subseq_idx -1")
445 __msg("mark_precise: frame0: regs=r1,r4 stack=-8 before 18: (95) exit")
446 __msg("mark_precise: frame1: regs= stack= before 17: (b7) r0 = 0")
447 __msg("mark_precise: frame1: regs= stack= before 10: (85) call bpf_loop#181")
448 __msg("mark_precise: frame0: parent state regs= stack=:")
449 __msg("from 18 to 10: safe")
parent_stack_slot_precise_with_callback(void)450 __naked int parent_stack_slot_precise_with_callback(void)
451 {
452 asm volatile (
453 /* spill reg */
454 "r6 = 3;"
455 "*(u64 *)(r10 - 8) = r6;"
456
457 /* ensure we have callback frame in jump history */
458 "r1 = r6;" /* nr_loops */
459 "r2 = %[callback_subprog];" /* callback_fn */
460 "r3 = 0;" /* callback_ctx */
461 "r4 = 0;" /* flags */
462 "call %[bpf_loop];"
463
464 /* restore reg from stack; in this case we'll be carrying
465 * stack mask when going back into subprog through jump
466 * history
467 */
468 "r6 = *(u64 *)(r10 - 8);"
469
470 "r6 *= 4;"
471 "r1 = %[vals];"
472 /* here r6 is forced to be precise and has to be propagated
473 * back to the beginning, handling (and ignoring) subprog call
474 */
475 "r1 += r6;"
476 "r0 = *(u32 *)(r1 + 0);"
477 "exit;"
478 :
479 : __imm_ptr(vals),
480 __imm_ptr(callback_subprog),
481 __imm(bpf_loop)
482 : __clobber_common, "r6"
483 );
484 }
485
486 __noinline __used
subprog_with_precise_arg(__u64 x)487 static __u64 subprog_with_precise_arg(__u64 x)
488 {
489 return vals[x]; /* x is forced to be precise */
490 }
491
492 SEC("?raw_tp")
493 __success __log_level(2)
494 __msg("8: (0f) r2 += r1")
495 __msg("mark_precise: frame1: last_idx 8 first_idx 0")
496 __msg("mark_precise: frame1: regs=r1 stack= before 6: (18) r2 = ")
497 __msg("mark_precise: frame1: regs=r1 stack= before 5: (67) r1 <<= 2")
498 __msg("mark_precise: frame1: regs=r1 stack= before 2: (85) call pc+2")
499 __msg("mark_precise: frame0: regs=r1 stack= before 1: (bf) r1 = r6")
500 __msg("mark_precise: frame0: regs=r6 stack= before 0: (b7) r6 = 3")
subprog_arg_precise(void)501 __naked int subprog_arg_precise(void)
502 {
503 asm volatile (
504 "r6 = 3;"
505 "r1 = r6;"
506 /* subprog_with_precise_arg expects its argument to be
507 * precise, so r1->r6 will be marked precise from inside the
508 * subprog
509 */
510 "call subprog_with_precise_arg;"
511 "r0 += r6;"
512 "exit;"
513 :
514 :
515 : __clobber_common, "r6"
516 );
517 }
518
519 /* r1 is pointer to stack slot;
520 * r2 is a register to spill into that slot
521 * subprog also spills r2 into its own stack slot
522 */
523 __naked __noinline __used
subprog_spill_reg_precise(void)524 static __u64 subprog_spill_reg_precise(void)
525 {
526 asm volatile (
527 /* spill to parent stack */
528 "*(u64 *)(r1 + 0) = r2;"
529 /* spill to subprog stack (we use -16 offset to avoid
530 * accidental confusion with parent's -8 stack slot in
531 * verifier log output)
532 */
533 "*(u64 *)(r10 - 16) = r2;"
534 /* use both spills as return result to propagete precision everywhere */
535 "r0 = *(u64 *)(r10 - 16);"
536 "r2 = *(u64 *)(r1 + 0);"
537 "r0 += r2;"
538 "exit;"
539 );
540 }
541
542 SEC("?raw_tp")
543 __success __log_level(2)
544 __msg("10: (0f) r1 += r7")
545 __msg("mark_precise: frame0: last_idx 10 first_idx 7 subseq_idx -1")
546 __msg("mark_precise: frame0: regs=r7 stack= before 9: (bf) r1 = r8")
547 __msg("mark_precise: frame0: regs=r7 stack= before 8: (27) r7 *= 4")
548 __msg("mark_precise: frame0: regs=r7 stack= before 7: (79) r7 = *(u64 *)(r10 -8)")
549 __msg("mark_precise: frame0: parent state regs= stack=-8: R0_w=2 R6_w=1 R8_rw=map_value(map=.data.vals,ks=4,vs=16) R10=fp0 fp-8_rw=P1")
550 __msg("mark_precise: frame0: last_idx 18 first_idx 0 subseq_idx 7")
551 __msg("mark_precise: frame0: regs= stack=-8 before 18: (95) exit")
552 __msg("mark_precise: frame1: regs= stack= before 17: (0f) r0 += r2")
553 __msg("mark_precise: frame1: regs= stack= before 16: (79) r2 = *(u64 *)(r1 +0)")
554 __msg("mark_precise: frame1: regs= stack= before 15: (79) r0 = *(u64 *)(r10 -16)")
555 __msg("mark_precise: frame1: regs= stack= before 14: (7b) *(u64 *)(r10 -16) = r2")
556 __msg("mark_precise: frame1: regs= stack= before 13: (7b) *(u64 *)(r1 +0) = r2")
557 __msg("mark_precise: frame1: regs=r2 stack= before 6: (85) call pc+6")
558 __msg("mark_precise: frame0: regs=r2 stack= before 5: (bf) r2 = r6")
559 __msg("mark_precise: frame0: regs=r6 stack= before 4: (07) r1 += -8")
560 __msg("mark_precise: frame0: regs=r6 stack= before 3: (bf) r1 = r10")
561 __msg("mark_precise: frame0: regs=r6 stack= before 2: (b7) r6 = 1")
subprog_spill_into_parent_stack_slot_precise(void)562 __naked int subprog_spill_into_parent_stack_slot_precise(void)
563 {
564 asm volatile (
565 "r6 = 1;"
566
567 /* pass pointer to stack slot and r6 to subprog;
568 * r6 will be marked precise and spilled into fp-8 slot, which
569 * also should be marked precise
570 */
571 "r1 = r10;"
572 "r1 += -8;"
573 "r2 = r6;"
574 "call subprog_spill_reg_precise;"
575
576 /* restore reg from stack; in this case we'll be carrying
577 * stack mask when going back into subprog through jump
578 * history
579 */
580 "r7 = *(u64 *)(r10 - 8);"
581
582 "r7 *= 4;"
583 "r1 = %[vals];"
584 /* here r7 is forced to be precise and has to be propagated
585 * back to the beginning, handling subprog call and logic
586 */
587 "r1 += r7;"
588 "r0 = *(u32 *)(r1 + 0);"
589 "exit;"
590 :
591 : __imm_ptr(vals)
592 : __clobber_common, "r6", "r7"
593 );
594 }
595
596 __naked __noinline __used
subprog_with_checkpoint(void)597 static __u64 subprog_with_checkpoint(void)
598 {
599 asm volatile (
600 "r0 = 0;"
601 /* guaranteed checkpoint if BPF_F_TEST_STATE_FREQ is used */
602 "goto +0;"
603 "exit;"
604 );
605 }
606
607 char _license[] SEC("license") = "GPL";
608