1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/bpf.h> |
3 | #include <bpf/bpf_helpers.h> |
4 | #include <bpf/bpf_tracing.h> |
5 | #include <errno.h> |
6 | |
7 | char _license[] SEC("license" ) = "GPL" ; |
8 | |
9 | __u64 test1_result = 0; |
10 | SEC("fentry/bpf_fentry_test1" ) |
11 | int BPF_PROG(test1) |
12 | { |
13 | __u64 cnt = bpf_get_func_arg_cnt(ctx); |
14 | __u64 a = 0, z = 0, ret = 0; |
15 | __s64 err; |
16 | |
17 | test1_result = cnt == 1; |
18 | |
19 | /* valid arguments */ |
20 | err = bpf_get_func_arg(ctx, 0, &a); |
21 | |
22 | /* We need to cast access to traced function argument values with |
23 | * proper type cast, because trampoline uses type specific instruction |
24 | * to save it, like for 'int a' with 32-bit mov like: |
25 | * |
26 | * mov %edi,-0x8(%rbp) |
27 | * |
28 | * so the upper 4 bytes are not zeroed. |
29 | */ |
30 | test1_result &= err == 0 && ((int) a == 1); |
31 | |
32 | /* not valid argument */ |
33 | err = bpf_get_func_arg(ctx, 1, &z); |
34 | test1_result &= err == -EINVAL; |
35 | |
36 | /* return value fails in fentry */ |
37 | err = bpf_get_func_ret(ctx, &ret); |
38 | test1_result &= err == -EOPNOTSUPP; |
39 | return 0; |
40 | } |
41 | |
42 | __u64 test2_result = 0; |
43 | SEC("fexit/bpf_fentry_test2" ) |
44 | int BPF_PROG(test2) |
45 | { |
46 | __u64 cnt = bpf_get_func_arg_cnt(ctx); |
47 | __u64 a = 0, b = 0, z = 0, ret = 0; |
48 | __s64 err; |
49 | |
50 | test2_result = cnt == 2; |
51 | |
52 | /* valid arguments */ |
53 | err = bpf_get_func_arg(ctx, 0, &a); |
54 | test2_result &= err == 0 && (int) a == 2; |
55 | |
56 | err = bpf_get_func_arg(ctx, 1, &b); |
57 | test2_result &= err == 0 && b == 3; |
58 | |
59 | /* not valid argument */ |
60 | err = bpf_get_func_arg(ctx, 2, &z); |
61 | test2_result &= err == -EINVAL; |
62 | |
63 | /* return value */ |
64 | err = bpf_get_func_ret(ctx, &ret); |
65 | test2_result &= err == 0 && ret == 5; |
66 | return 0; |
67 | } |
68 | |
69 | __u64 test3_result = 0; |
70 | SEC("fmod_ret/bpf_modify_return_test" ) |
71 | int BPF_PROG(fmod_ret_test, int _a, int *_b, int _ret) |
72 | { |
73 | __u64 cnt = bpf_get_func_arg_cnt(ctx); |
74 | __u64 a = 0, b = 0, z = 0, ret = 0; |
75 | __s64 err; |
76 | |
77 | test3_result = cnt == 2; |
78 | |
79 | /* valid arguments */ |
80 | err = bpf_get_func_arg(ctx, 0, &a); |
81 | test3_result &= err == 0 && ((int) a == 1); |
82 | |
83 | err = bpf_get_func_arg(ctx, 1, &b); |
84 | test3_result &= err == 0 && ((int *) b == _b); |
85 | |
86 | /* not valid argument */ |
87 | err = bpf_get_func_arg(ctx, 2, &z); |
88 | test3_result &= err == -EINVAL; |
89 | |
90 | /* return value */ |
91 | err = bpf_get_func_ret(ctx, &ret); |
92 | test3_result &= err == 0 && ret == 0; |
93 | |
94 | /* change return value, it's checked in fexit_test program */ |
95 | return 1234; |
96 | } |
97 | |
98 | __u64 test4_result = 0; |
99 | SEC("fexit/bpf_modify_return_test" ) |
100 | int BPF_PROG(fexit_test, int _a, int *_b, int _ret) |
101 | { |
102 | __u64 cnt = bpf_get_func_arg_cnt(ctx); |
103 | __u64 a = 0, b = 0, z = 0, ret = 0; |
104 | __s64 err; |
105 | |
106 | test4_result = cnt == 2; |
107 | |
108 | /* valid arguments */ |
109 | err = bpf_get_func_arg(ctx, 0, &a); |
110 | test4_result &= err == 0 && ((int) a == 1); |
111 | |
112 | err = bpf_get_func_arg(ctx, 1, &b); |
113 | test4_result &= err == 0 && ((int *) b == _b); |
114 | |
115 | /* not valid argument */ |
116 | err = bpf_get_func_arg(ctx, 2, &z); |
117 | test4_result &= err == -EINVAL; |
118 | |
119 | /* return value */ |
120 | err = bpf_get_func_ret(ctx, &ret); |
121 | test4_result &= err == 0 && ret == 1234; |
122 | return 0; |
123 | } |
124 | |