test_subprogs.c (2636B)
1#include "vmlinux.h" 2#include <bpf/bpf_helpers.h> 3#include <bpf/bpf_core_read.h> 4 5const char LICENSE[] SEC("license") = "GPL"; 6 7struct { 8 __uint(type, BPF_MAP_TYPE_ARRAY); 9 __uint(max_entries, 1); 10 __type(key, __u32); 11 __type(value, __u64); 12} array SEC(".maps"); 13 14__noinline int sub1(int x) 15{ 16 int key = 0; 17 18 bpf_map_lookup_elem(&array, &key); 19 return x + 1; 20} 21 22static __noinline int sub5(int v); 23 24__noinline int sub2(int y) 25{ 26 return sub5(y + 2); 27} 28 29static __noinline int sub3(int z) 30{ 31 return z + 3 + sub1(4); 32} 33 34static __noinline int sub4(int w) 35{ 36 int key = 0; 37 38 bpf_map_lookup_elem(&array, &key); 39 return w + sub3(5) + sub1(6); 40} 41 42/* sub5() is an identitify function, just to test weirder functions layout and 43 * call patterns 44 */ 45static __noinline int sub5(int v) 46{ 47 return sub1(v) - 1; /* compensates sub1()'s + 1 */ 48} 49 50/* unfortunately verifier rejects `struct task_struct *t` as an unkown pointer 51 * type, so we need to accept pointer as integer and then cast it inside the 52 * function 53 */ 54__noinline int get_task_tgid(uintptr_t t) 55{ 56 /* this ensures that CO-RE relocs work in multi-subprogs .text */ 57 return BPF_CORE_READ((struct task_struct *)(void *)t, tgid); 58} 59 60int res1 = 0; 61int res2 = 0; 62int res3 = 0; 63int res4 = 0; 64 65SEC("raw_tp/sys_enter") 66int prog1(void *ctx) 67{ 68 /* perform some CO-RE relocations to ensure they work with multi-prog 69 * sections correctly 70 */ 71 struct task_struct *t = (void *)bpf_get_current_task(); 72 73 if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) 74 return 1; 75 76 res1 = sub1(1) + sub3(2); /* (1 + 1) + (2 + 3 + (4 + 1)) = 12 */ 77 return 0; 78} 79 80SEC("raw_tp/sys_exit") 81int prog2(void *ctx) 82{ 83 struct task_struct *t = (void *)bpf_get_current_task(); 84 85 if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) 86 return 1; 87 88 res2 = sub2(3) + sub3(4); /* (3 + 2) + (4 + 3 + (4 + 1)) = 17 */ 89 return 0; 90} 91 92static int empty_callback(__u32 index, void *data) 93{ 94 return 0; 95} 96 97/* prog3 has the same section name as prog1 */ 98SEC("raw_tp/sys_enter") 99int prog3(void *ctx) 100{ 101 struct task_struct *t = (void *)bpf_get_current_task(); 102 103 if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) 104 return 1; 105 106 /* test that ld_imm64 with BPF_PSEUDO_FUNC doesn't get blinded */ 107 bpf_loop(1, empty_callback, NULL, 0); 108 109 res3 = sub3(5) + 6; /* (5 + 3 + (4 + 1)) + 6 = 19 */ 110 return 0; 111} 112 113/* prog4 has the same section name as prog2 */ 114SEC("raw_tp/sys_exit") 115int prog4(void *ctx) 116{ 117 struct task_struct *t = (void *)bpf_get_current_task(); 118 119 if (!BPF_CORE_READ(t, pid) || !get_task_tgid((uintptr_t)t)) 120 return 1; 121 122 res4 = sub4(7) + sub1(8); /* (7 + (5 + 3 + (4 + 1)) + (6 + 1)) + (8 + 1) = 36 */ 123 return 0; 124}