linux/tools/testing/selftests/bpf/progs/test_subprogs.c
<<
>>
Prefs
   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}
 125