1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (c) 2020, Oracle and/or its affiliates. */ |
3 | |
4 | #include "btf_ptr.h" |
5 | #include <bpf/bpf_helpers.h> |
6 | #include <bpf/bpf_tracing.h> |
7 | #include <bpf/bpf_core_read.h> |
8 | |
9 | #include <errno.h> |
10 | |
11 | long ret = 0; |
12 | int num_subtests = 0; |
13 | int ran_subtests = 0; |
14 | bool skip = false; |
15 | |
16 | #define STRSIZE 2048 |
17 | #define EXPECTED_STRSIZE 256 |
18 | |
19 | #if defined(bpf_target_s390) |
20 | /* NULL points to a readable struct lowcore on s390, so take the last page */ |
21 | #define BADPTR ((void *)0xFFFFFFFFFFFFF000ULL) |
22 | #else |
23 | #define BADPTR 0 |
24 | #endif |
25 | |
26 | #ifndef ARRAY_SIZE |
27 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) |
28 | #endif |
29 | |
30 | struct { |
31 | __uint(type, BPF_MAP_TYPE_PERCPU_ARRAY); |
32 | __uint(max_entries, 1); |
33 | __type(key, __u32); |
34 | __type(value, char[STRSIZE]); |
35 | } strdata SEC(".maps" ); |
36 | |
37 | static int __strncmp(const void *m1, const void *m2, size_t len) |
38 | { |
39 | const unsigned char *s1 = m1; |
40 | const unsigned char *s2 = m2; |
41 | int i, delta = 0; |
42 | |
43 | for (i = 0; i < len; i++) { |
44 | delta = s1[i] - s2[i]; |
45 | if (delta || s1[i] == 0 || s2[i] == 0) |
46 | break; |
47 | } |
48 | return delta; |
49 | } |
50 | |
51 | #if __has_builtin(__builtin_btf_type_id) |
52 | #define TEST_BTF(_str, _type, _flags, _expected, ...) \ |
53 | do { \ |
54 | static const char _expectedval[EXPECTED_STRSIZE] = \ |
55 | _expected; \ |
56 | __u64 _hflags = _flags | BTF_F_COMPACT; \ |
57 | static _type _ptrdata = __VA_ARGS__; \ |
58 | static struct btf_ptr _ptr = { }; \ |
59 | int _cmp; \ |
60 | \ |
61 | ++num_subtests; \ |
62 | if (ret < 0) \ |
63 | break; \ |
64 | ++ran_subtests; \ |
65 | _ptr.ptr = &_ptrdata; \ |
66 | _ptr.type_id = bpf_core_type_id_kernel(_type); \ |
67 | if (_ptr.type_id <= 0) { \ |
68 | ret = -EINVAL; \ |
69 | break; \ |
70 | } \ |
71 | ret = bpf_snprintf_btf(_str, STRSIZE, \ |
72 | &_ptr, sizeof(_ptr), _hflags); \ |
73 | if (ret) \ |
74 | break; \ |
75 | _cmp = __strncmp(_str, _expectedval, EXPECTED_STRSIZE); \ |
76 | if (_cmp != 0) { \ |
77 | bpf_printk("(%d) got %s", _cmp, _str); \ |
78 | bpf_printk("(%d) expected %s", _cmp, \ |
79 | _expectedval); \ |
80 | ret = -EBADMSG; \ |
81 | break; \ |
82 | } \ |
83 | } while (0) |
84 | #endif |
85 | |
86 | /* Use where expected data string matches its stringified declaration */ |
87 | #define TEST_BTF_C(_str, _type, _flags, ...) \ |
88 | TEST_BTF(_str, _type, _flags, "(" #_type ")" #__VA_ARGS__, \ |
89 | __VA_ARGS__) |
90 | |
91 | /* TRACE_EVENT(netif_receive_skb, |
92 | * TP_PROTO(struct sk_buff *skb), |
93 | */ |
94 | SEC("tp_btf/netif_receive_skb" ) |
95 | int BPF_PROG(trace_netif_receive_skb, struct sk_buff *skb) |
96 | { |
97 | static __u64 flags[] = { 0, BTF_F_COMPACT, BTF_F_ZERO, BTF_F_PTR_RAW, |
98 | BTF_F_NONAME, BTF_F_COMPACT | BTF_F_ZERO | |
99 | BTF_F_PTR_RAW | BTF_F_NONAME }; |
100 | static struct btf_ptr p = { }; |
101 | __u32 key = 0; |
102 | int i, __ret; |
103 | char *str; |
104 | |
105 | #if __has_builtin(__builtin_btf_type_id) |
106 | str = bpf_map_lookup_elem(&strdata, &key); |
107 | if (!str) |
108 | return 0; |
109 | |
110 | /* Ensure we can write skb string representation */ |
111 | p.type_id = bpf_core_type_id_kernel(struct sk_buff); |
112 | p.ptr = skb; |
113 | for (i = 0; i < ARRAY_SIZE(flags); i++) { |
114 | ++num_subtests; |
115 | ret = bpf_snprintf_btf(str, STRSIZE, &p, sizeof(p), 0); |
116 | if (ret < 0) |
117 | bpf_printk("returned %d when writing skb" , ret); |
118 | ++ran_subtests; |
119 | } |
120 | |
121 | /* Check invalid ptr value */ |
122 | p.ptr = BADPTR; |
123 | __ret = bpf_snprintf_btf(str, STRSIZE, &p, sizeof(p), 0); |
124 | if (__ret >= 0) { |
125 | bpf_printk("printing %llx should generate error, got (%d)" , |
126 | (unsigned long long)BADPTR, __ret); |
127 | ret = -ERANGE; |
128 | } |
129 | |
130 | /* Verify type display for various types. */ |
131 | |
132 | /* simple int */ |
133 | TEST_BTF_C(str, int, 0, 1234); |
134 | TEST_BTF(str, int, BTF_F_NONAME, "1234" , 1234); |
135 | /* zero value should be printed at toplevel */ |
136 | TEST_BTF(str, int, 0, "(int)0" , 0); |
137 | TEST_BTF(str, int, BTF_F_NONAME, "0" , 0); |
138 | TEST_BTF(str, int, BTF_F_ZERO, "(int)0" , 0); |
139 | TEST_BTF(str, int, BTF_F_NONAME | BTF_F_ZERO, "0" , 0); |
140 | TEST_BTF_C(str, int, 0, -4567); |
141 | TEST_BTF(str, int, BTF_F_NONAME, "-4567" , -4567); |
142 | |
143 | /* simple char */ |
144 | TEST_BTF_C(str, char, 0, 100); |
145 | TEST_BTF(str, char, BTF_F_NONAME, "100" , 100); |
146 | /* zero value should be printed at toplevel */ |
147 | TEST_BTF(str, char, 0, "(char)0" , 0); |
148 | TEST_BTF(str, char, BTF_F_NONAME, "0" , 0); |
149 | TEST_BTF(str, char, BTF_F_ZERO, "(char)0" , 0); |
150 | TEST_BTF(str, char, BTF_F_NONAME | BTF_F_ZERO, "0" , 0); |
151 | |
152 | /* simple typedef */ |
153 | TEST_BTF_C(str, uint64_t, 0, 100); |
154 | TEST_BTF(str, u64, BTF_F_NONAME, "1" , 1); |
155 | /* zero value should be printed at toplevel */ |
156 | TEST_BTF(str, u64, 0, "(u64)0" , 0); |
157 | TEST_BTF(str, u64, BTF_F_NONAME, "0" , 0); |
158 | TEST_BTF(str, u64, BTF_F_ZERO, "(u64)0" , 0); |
159 | TEST_BTF(str, u64, BTF_F_NONAME|BTF_F_ZERO, "0" , 0); |
160 | |
161 | /* typedef struct */ |
162 | TEST_BTF_C(str, atomic_t, 0, {.counter = (int)1,}); |
163 | TEST_BTF(str, atomic_t, BTF_F_NONAME, "{1,}" , {.counter = 1,}); |
164 | /* typedef with 0 value should be printed at toplevel */ |
165 | TEST_BTF(str, atomic_t, 0, "(atomic_t){}" , {.counter = 0,}); |
166 | TEST_BTF(str, atomic_t, BTF_F_NONAME, "{}" , {.counter = 0,}); |
167 | TEST_BTF(str, atomic_t, BTF_F_ZERO, "(atomic_t){.counter = (int)0,}" , |
168 | {.counter = 0,}); |
169 | TEST_BTF(str, atomic_t, BTF_F_NONAME|BTF_F_ZERO, |
170 | "{0,}" , {.counter = 0,}); |
171 | |
172 | /* enum where enum value does (and does not) exist */ |
173 | TEST_BTF_C(str, enum bpf_cmd, 0, BPF_MAP_CREATE); |
174 | TEST_BTF(str, enum bpf_cmd, 0, "(enum bpf_cmd)BPF_MAP_CREATE" , 0); |
175 | TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME, "BPF_MAP_CREATE" , |
176 | BPF_MAP_CREATE); |
177 | TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME|BTF_F_ZERO, |
178 | "BPF_MAP_CREATE" , 0); |
179 | |
180 | TEST_BTF(str, enum bpf_cmd, BTF_F_ZERO, "(enum bpf_cmd)BPF_MAP_CREATE" , |
181 | BPF_MAP_CREATE); |
182 | TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME|BTF_F_ZERO, |
183 | "BPF_MAP_CREATE" , BPF_MAP_CREATE); |
184 | TEST_BTF_C(str, enum bpf_cmd, 0, 2000); |
185 | TEST_BTF(str, enum bpf_cmd, BTF_F_NONAME, "2000" , 2000); |
186 | |
187 | /* simple struct */ |
188 | TEST_BTF_C(str, struct btf_enum, 0, |
189 | {.name_off = (__u32)3,.val = (__s32)-1,}); |
190 | TEST_BTF(str, struct btf_enum, BTF_F_NONAME, "{3,-1,}" , |
191 | { .name_off = 3, .val = -1,}); |
192 | TEST_BTF(str, struct btf_enum, BTF_F_NONAME, "{-1,}" , |
193 | { .name_off = 0, .val = -1,}); |
194 | TEST_BTF(str, struct btf_enum, BTF_F_NONAME|BTF_F_ZERO, "{0,-1,}" , |
195 | { .name_off = 0, .val = -1,}); |
196 | /* empty struct should be printed */ |
197 | TEST_BTF(str, struct btf_enum, 0, "(struct btf_enum){}" , |
198 | { .name_off = 0, .val = 0,}); |
199 | TEST_BTF(str, struct btf_enum, BTF_F_NONAME, "{}" , |
200 | { .name_off = 0, .val = 0,}); |
201 | TEST_BTF(str, struct btf_enum, BTF_F_ZERO, |
202 | "(struct btf_enum){.name_off = (__u32)0,.val = (__s32)0,}" , |
203 | { .name_off = 0, .val = 0,}); |
204 | |
205 | /* struct with pointers */ |
206 | TEST_BTF(str, struct list_head, BTF_F_PTR_RAW, |
207 | "(struct list_head){.next = (struct list_head *)0x0000000000000001,}" , |
208 | { .next = (struct list_head *)1 }); |
209 | /* NULL pointer should not be displayed */ |
210 | TEST_BTF(str, struct list_head, BTF_F_PTR_RAW, |
211 | "(struct list_head){}" , |
212 | { .next = (struct list_head *)0 }); |
213 | |
214 | /* struct with char array */ |
215 | TEST_BTF(str, struct bpf_prog_info, 0, |
216 | "(struct bpf_prog_info){.name = (char[])['f','o','o',],}" , |
217 | { .name = "foo" ,}); |
218 | TEST_BTF(str, struct bpf_prog_info, BTF_F_NONAME, |
219 | "{['f','o','o',],}" , |
220 | {.name = "foo" ,}); |
221 | /* leading null char means do not display string */ |
222 | TEST_BTF(str, struct bpf_prog_info, 0, |
223 | "(struct bpf_prog_info){}" , |
224 | {.name = {'\0', 'f', 'o', 'o'}}); |
225 | /* handle non-printable characters */ |
226 | TEST_BTF(str, struct bpf_prog_info, 0, |
227 | "(struct bpf_prog_info){.name = (char[])[1,2,3,],}" , |
228 | { .name = {1, 2, 3, 0}}); |
229 | |
230 | /* struct with non-char array */ |
231 | TEST_BTF(str, struct __sk_buff, 0, |
232 | "(struct __sk_buff){.cb = (__u32[])[1,2,3,4,5,],}" , |
233 | { .cb = {1, 2, 3, 4, 5,},}); |
234 | TEST_BTF(str, struct __sk_buff, BTF_F_NONAME, |
235 | "{[1,2,3,4,5,],}" , |
236 | { .cb = { 1, 2, 3, 4, 5},}); |
237 | /* For non-char, arrays, show non-zero values only */ |
238 | TEST_BTF(str, struct __sk_buff, 0, |
239 | "(struct __sk_buff){.cb = (__u32[])[1,],}" , |
240 | { .cb = { 0, 0, 1, 0, 0},}); |
241 | |
242 | /* struct with bitfields */ |
243 | TEST_BTF_C(str, struct bpf_insn, 0, |
244 | {.code = (__u8)1,.dst_reg = (__u8)0x2,.src_reg = (__u8)0x3,.off = (__s16)4,.imm = (__s32)5,}); |
245 | TEST_BTF(str, struct bpf_insn, BTF_F_NONAME, "{1,0x2,0x3,4,5,}" , |
246 | {.code = 1, .dst_reg = 0x2, .src_reg = 0x3, .off = 4, |
247 | .imm = 5,}); |
248 | #else |
249 | skip = true; |
250 | #endif |
251 | |
252 | return 0; |
253 | } |
254 | |
255 | char _license[] SEC("license" ) = "GPL" ; |
256 | |