blob: 7b39b1f712a1a461ddfdf07caee2238b57845c8e [file] [log] [blame]
Martin KaFai Lauc0fa1b62018-04-18 15:56:06 -07001/* SPDX-License-Identifier: GPL-2.0 */
2/* Copyright (c) 2018 Facebook */
3
4#include <linux/bpf.h>
5#include <linux/btf.h>
6#include <linux/err.h>
7#include <bpf/bpf.h>
8#include <sys/resource.h>
9#include <libelf.h>
10#include <gelf.h>
11#include <string.h>
12#include <stdlib.h>
13#include <stdio.h>
14#include <stdarg.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <errno.h>
18#include <bpf/libbpf.h>
19#include <bpf/btf.h>
20
21#include "bpf_rlimit.h"
22
23#define min(a, b) ((a) < (b) ? (a) : (b))
24#define __printf(a, b) __attribute__((format(printf, a, b)))
25
26__printf(1, 2)
27static int __base_pr(const char *format, ...)
28{
29 va_list args;
30 int err;
31
32 va_start(args, format);
33 err = vfprintf(stderr, format, args);
34 va_end(args);
35 return err;
36}
37
38#define BTF_INFO_ENC(kind, root, vlen) \
39 ((!!(root) << 31) | ((kind) << 24) | ((vlen) & BTF_MAX_VLEN))
40
41#define BTF_TYPE_ENC(name, info, size_or_type) \
42 (name), (info), (size_or_type)
43
44#define BTF_INT_ENC(encoding, bits_offset, nr_bits) \
45 ((encoding) << 24 | (bits_offset) << 16 | (nr_bits))
46#define BTF_TYPE_INT_ENC(name, encoding, bits_offset, bits, sz) \
47 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_INT, 0, 0), sz), \
48 BTF_INT_ENC(encoding, bits_offset, bits)
49
50#define BTF_ARRAY_ENC(type, index_type, nr_elems) \
51 (type), (index_type), (nr_elems)
52#define BTF_TYPE_ARRAY_ENC(type, index_type, nr_elems) \
53 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ARRAY, 0, 0), 0), \
54 BTF_ARRAY_ENC(type, index_type, nr_elems)
55
56#define BTF_MEMBER_ENC(name, type, bits_offset) \
57 (name), (type), (bits_offset)
58#define BTF_ENUM_ENC(name, val) (name), (val)
59
60#define BTF_TYPEDEF_ENC(name, type) \
61 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), type)
62
63#define BTF_PTR_ENC(name, type) \
64 BTF_TYPE_ENC(name, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), type)
65
66#define BTF_END_RAW 0xdeadbeef
67#define NAME_TBD 0xdeadb33f
68
69#define MAX_NR_RAW_TYPES 1024
70#define BTF_LOG_BUF_SIZE 65535
71
72#ifndef ARRAY_SIZE
73# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
74#endif
75
76static struct args {
77 unsigned int raw_test_num;
78 unsigned int file_test_num;
79 unsigned int get_info_test_num;
80 bool raw_test;
81 bool file_test;
82 bool get_info_test;
83 bool pprint_test;
84 bool always_log;
85} args;
86
87static char btf_log_buf[BTF_LOG_BUF_SIZE];
88
89static struct btf_header hdr_tmpl = {
90 .magic = BTF_MAGIC,
91 .version = BTF_VERSION,
92};
93
94struct btf_raw_test {
95 const char *descr;
96 const char *str_sec;
97 const char *map_name;
98 __u32 raw_types[MAX_NR_RAW_TYPES];
99 __u32 str_sec_size;
100 enum bpf_map_type map_type;
101 __u32 key_size;
102 __u32 value_size;
103 __u32 key_id;
104 __u32 value_id;
105 __u32 max_entries;
106 bool btf_load_err;
107 bool map_create_err;
108 int type_off_delta;
109 int str_off_delta;
110 int str_len_delta;
111};
112
113static struct btf_raw_test raw_tests[] = {
114/* enum E {
115 * E0,
116 * E1,
117 * };
118 *
119 * struct A {
120 * int m;
121 * unsigned long long n;
122 * char o;
123 * [3 bytes hole]
124 * int p[8];
125 * int q[4][8];
126 * enum E r;
127 * };
128 */
129{
130 .descr = "struct test #1",
131 .raw_types = {
132 /* int */
133 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
134 /* unsigned long long */
135 BTF_TYPE_INT_ENC(0, 0, 0, 64, 8), /* [2] */
136 /* char */
137 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 8, 1), /* [3] */
138 /* int[8] */
139 BTF_TYPE_ARRAY_ENC(1, 1, 8), /* [4] */
140 /* struct A { */ /* [5] */
141 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 6), 180),
142 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
143 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* unsigned long long n;*/
144 BTF_MEMBER_ENC(NAME_TBD, 3, 96),/* char o; */
145 BTF_MEMBER_ENC(NAME_TBD, 4, 128),/* int p[8] */
146 BTF_MEMBER_ENC(NAME_TBD, 6, 384),/* int q[4][8] */
147 BTF_MEMBER_ENC(NAME_TBD, 7, 1408), /* enum E r */
148 /* } */
149 /* int[4][8] */
150 BTF_TYPE_ARRAY_ENC(4, 1, 4), /* [6] */
151 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 2), sizeof(int)),
152 BTF_ENUM_ENC(NAME_TBD, 0),
153 BTF_ENUM_ENC(NAME_TBD, 1),
154 BTF_END_RAW,
155 },
156 .str_sec = "\0A\0m\0n\0o\0p\0q\0r\0E\0E0\0E1",
157 .str_sec_size = sizeof("\0A\0m\0n\0o\0p\0q\0r\0E\0E0\0E1"),
158 .map_type = BPF_MAP_TYPE_ARRAY,
159 .map_name = "struct_test1_map",
160 .key_size = sizeof(int),
161 .value_size = 180,
162 .key_id = 1,
163 .value_id = 5,
164 .max_entries = 4,
165},
166
167/* typedef struct b Struct_B;
168 *
169 * struct A {
170 * int m;
171 * struct b n[4];
172 * const Struct_B o[4];
173 * };
174 *
175 * struct B {
176 * int m;
177 * int n;
178 * };
179 */
180{
181 .descr = "struct test #2",
182 .raw_types = {
183 /* int */ /* [1] */
184 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
185 /* struct b [4] */ /* [2] */
186 BTF_TYPE_ARRAY_ENC(4, 1, 4),
187
188 /* struct A { */ /* [3] */
189 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 3), 68),
190 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
191 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* struct B n[4] */
192 BTF_MEMBER_ENC(NAME_TBD, 8, 288),/* const Struct_B o[4];*/
193 /* } */
194
195 /* struct B { */ /* [4] */
196 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
197 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
198 BTF_MEMBER_ENC(NAME_TBD, 1, 32),/* int n; */
199 /* } */
200
201 /* const int */ /* [5] */
202 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 1),
203 /* typedef struct b Struct_B */ /* [6] */
204 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_TYPEDEF, 0, 0), 4),
205 /* const Struct_B */ /* [7] */
206 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 6),
207 /* const Struct_B [4] */ /* [8] */
208 BTF_TYPE_ARRAY_ENC(7, 1, 4),
209 BTF_END_RAW,
210 },
211 .str_sec = "\0A\0m\0n\0o\0B\0m\0n\0Struct_B",
212 .str_sec_size = sizeof("\0A\0m\0n\0o\0B\0m\0n\0Struct_B"),
213 .map_type = BPF_MAP_TYPE_ARRAY,
214 .map_name = "struct_test2_map",
215 .key_size = sizeof(int),
216 .value_size = 68,
217 .key_id = 1,
218 .value_id = 3,
219 .max_entries = 4,
220},
221
222/* Test member exceeds the size of struct.
223 *
224 * struct A {
225 * int m;
226 * int n;
227 * };
228 */
229{
230 .descr = "size check test #1",
231 .raw_types = {
232 /* int */ /* [1] */
233 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
234 /* struct A { */ /* [2] */
235 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) * 2 - 1),
236 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
237 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* int n; */
238 /* } */
239 BTF_END_RAW,
240 },
241 .str_sec = "\0A\0m\0n",
242 .str_sec_size = sizeof("\0A\0m\0n"),
243 .map_type = BPF_MAP_TYPE_ARRAY,
244 .map_name = "size_check1_map",
245 .key_size = sizeof(int),
246 .value_size = 1,
247 .key_id = 1,
248 .value_id = 2,
249 .max_entries = 4,
250 .btf_load_err = true,
251},
252
253/* Test member exeeds the size of struct
254 *
255 * struct A {
256 * int m;
257 * int n[2];
258 * };
259 */
260{
261 .descr = "size check test #2",
262 .raw_types = {
263 /* int */ /* [1] */
264 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, sizeof(int)),
265 /* int[2] */ /* [2] */
266 BTF_TYPE_ARRAY_ENC(1, 1, 2),
267 /* struct A { */ /* [3] */
268 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) * 3 - 1),
269 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
270 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* int n[2]; */
271 /* } */
272 BTF_END_RAW,
273 },
274 .str_sec = "\0A\0m\0n",
275 .str_sec_size = sizeof("\0A\0m\0n"),
276 .map_type = BPF_MAP_TYPE_ARRAY,
277 .map_name = "size_check2_map",
278 .key_size = sizeof(int),
279 .value_size = 1,
280 .key_id = 1,
281 .value_id = 3,
282 .max_entries = 4,
283 .btf_load_err = true,
284
285},
286
287/* Test member exeeds the size of struct
288 *
289 * struct A {
290 * int m;
291 * void *n;
292 * };
293 */
294{
295 .descr = "size check test #3",
296 .raw_types = {
297 /* int */ /* [1] */
298 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, sizeof(int)),
299 /* void* */ /* [2] */
300 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 0),
301 /* struct A { */ /* [3] */
302 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) + sizeof(void *) - 1),
303 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
304 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* void *n; */
305 /* } */
306 BTF_END_RAW,
307 },
308 .str_sec = "\0A\0m\0n",
309 .str_sec_size = sizeof("\0A\0m\0n"),
310 .map_type = BPF_MAP_TYPE_ARRAY,
311 .map_name = "size_check3_map",
312 .key_size = sizeof(int),
313 .value_size = 1,
314 .key_id = 1,
315 .value_id = 3,
316 .max_entries = 4,
317 .btf_load_err = true,
318},
319
320/* Test member exceeds the size of struct
321 *
322 * enum E {
323 * E0,
324 * E1,
325 * };
326 *
327 * struct A {
328 * int m;
329 * enum E n;
330 * };
331 */
332{
333 .descr = "size check test #4",
334 .raw_types = {
335 /* int */ /* [1] */
336 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, sizeof(int)),
337 /* enum E { */ /* [2] */
338 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 2), sizeof(int)),
339 BTF_ENUM_ENC(NAME_TBD, 0),
340 BTF_ENUM_ENC(NAME_TBD, 1),
341 /* } */
342 /* struct A { */ /* [3] */
343 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), sizeof(int) * 2 - 1),
344 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int m; */
345 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* enum E n; */
346 /* } */
347 BTF_END_RAW,
348 },
349 .str_sec = "\0E\0E0\0E1\0A\0m\0n",
350 .str_sec_size = sizeof("\0E\0E0\0E1\0A\0m\0n"),
351 .map_type = BPF_MAP_TYPE_ARRAY,
352 .map_name = "size_check4_map",
353 .key_size = sizeof(int),
354 .value_size = 1,
355 .key_id = 1,
356 .value_id = 3,
357 .max_entries = 4,
358 .btf_load_err = true,
359},
360
361/* typedef const void * const_void_ptr;
362 * struct A {
363 * const_void_ptr m;
364 * };
365 */
366{
367 .descr = "void test #1",
368 .raw_types = {
369 /* int */ /* [1] */
370 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
371 /* const void */ /* [2] */
372 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
373 /* const void* */ /* [3] */
374 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2),
375 /* typedef const void * const_void_ptr */
376 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3),
377 /* struct A { */ /* [4] */
378 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), sizeof(void *)),
379 /* const_void_ptr m; */
380 BTF_MEMBER_ENC(NAME_TBD, 3, 0),
381 /* } */
382 BTF_END_RAW,
383 },
384 .str_sec = "\0const_void_ptr\0A\0m",
385 .str_sec_size = sizeof("\0const_void_ptr\0A\0m"),
386 .map_type = BPF_MAP_TYPE_ARRAY,
387 .map_name = "void_test1_map",
388 .key_size = sizeof(int),
389 .value_size = sizeof(void *),
390 .key_id = 1,
391 .value_id = 4,
392 .max_entries = 4,
393},
394
395/* struct A {
396 * const void m;
397 * };
398 */
399{
400 .descr = "void test #2",
401 .raw_types = {
402 /* int */ /* [1] */
403 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
404 /* const void */ /* [2] */
405 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
406 /* struct A { */ /* [3] */
407 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), 8),
408 /* const void m; */
409 BTF_MEMBER_ENC(NAME_TBD, 2, 0),
410 /* } */
411 BTF_END_RAW,
412 },
413 .str_sec = "\0A\0m",
414 .str_sec_size = sizeof("\0A\0m"),
415 .map_type = BPF_MAP_TYPE_ARRAY,
416 .map_name = "void_test2_map",
417 .key_size = sizeof(int),
418 .value_size = sizeof(void *),
419 .key_id = 1,
420 .value_id = 3,
421 .max_entries = 4,
422 .btf_load_err = true,
423},
424
425/* typedef const void * const_void_ptr;
426 * const_void_ptr[4]
427 */
428{
429 .descr = "void test #3",
430 .raw_types = {
431 /* int */ /* [1] */
432 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
433 /* const void */ /* [2] */
434 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
435 /* const void* */ /* [3] */
436 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 2),
437 /* typedef const void * const_void_ptr */
438 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3),
439 /* const_void_ptr[4] */ /* [4] */
440 BTF_TYPE_ARRAY_ENC(3, 1, 4),
441 BTF_END_RAW,
442 },
443 .str_sec = "\0const_void_ptr",
444 .str_sec_size = sizeof("\0const_void_ptr"),
445 .map_type = BPF_MAP_TYPE_ARRAY,
446 .map_name = "void_test3_map",
447 .key_size = sizeof(int),
448 .value_size = sizeof(void *) * 4,
449 .key_id = 1,
450 .value_id = 4,
451 .max_entries = 4,
452},
453
454/* const void[4] */
455{
456 .descr = "void test #4",
457 .raw_types = {
458 /* int */ /* [1] */
459 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
460 /* const void */ /* [2] */
461 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 0),
462 /* const void[4] */ /* [3] */
463 BTF_TYPE_ARRAY_ENC(2, 1, 4),
464 BTF_END_RAW,
465 },
466 .str_sec = "\0A\0m",
467 .str_sec_size = sizeof("\0A\0m"),
468 .map_type = BPF_MAP_TYPE_ARRAY,
469 .map_name = "void_test4_map",
470 .key_size = sizeof(int),
471 .value_size = sizeof(void *) * 4,
472 .key_id = 1,
473 .value_id = 3,
474 .max_entries = 4,
475 .btf_load_err = true,
476},
477
478/* Array_A <------------------+
479 * elem_type == Array_B |
480 * | |
481 * | |
482 * Array_B <-------- + |
483 * elem_type == Array A --+
484 */
485{
486 .descr = "loop test #1",
487 .raw_types = {
488 /* int */ /* [1] */
489 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
490 /* Array_A */ /* [2] */
491 BTF_TYPE_ARRAY_ENC(3, 1, 8),
492 /* Array_B */ /* [3] */
493 BTF_TYPE_ARRAY_ENC(2, 1, 8),
494 BTF_END_RAW,
495 },
496 .str_sec = "",
497 .str_sec_size = sizeof(""),
498 .map_type = BPF_MAP_TYPE_ARRAY,
499 .map_name = "loop_test1_map",
500 .key_size = sizeof(int),
501 .value_size = sizeof(sizeof(int) * 8),
502 .key_id = 1,
503 .value_id = 2,
504 .max_entries = 4,
505 .btf_load_err = true,
506},
507
508/* typedef is _before_ the BTF type of Array_A and Array_B
509 *
510 * typedef Array_B int_array;
511 *
512 * Array_A <------------------+
513 * elem_type == int_array |
514 * | |
515 * | |
516 * Array_B <-------- + |
517 * elem_type == Array_A --+
518 */
519{
520 .descr = "loop test #2",
521 .raw_types = {
522 /* int */
523 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
524 /* typedef Array_B int_array */
525 BTF_TYPEDEF_ENC(1, 4), /* [2] */
526 /* Array_A */
527 BTF_TYPE_ARRAY_ENC(2, 1, 8), /* [3] */
528 /* Array_B */
529 BTF_TYPE_ARRAY_ENC(3, 1, 8), /* [4] */
530
531 BTF_END_RAW,
532 },
533 .str_sec = "\0int_array\0",
534 .str_sec_size = sizeof("\0int_array"),
535 .map_type = BPF_MAP_TYPE_ARRAY,
536 .map_name = "loop_test2_map",
537 .key_size = sizeof(int),
538 .value_size = sizeof(sizeof(int) * 8),
539 .key_id = 1,
540 .value_id = 2,
541 .max_entries = 4,
542 .btf_load_err = true,
543},
544
545/* Array_A <------------------+
546 * elem_type == Array_B |
547 * | |
548 * | |
549 * Array_B <-------- + |
550 * elem_type == Array_A --+
551 */
552{
553 .descr = "loop test #3",
554 .raw_types = {
555 /* int */ /* [1] */
556 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
557 /* Array_A */ /* [2] */
558 BTF_TYPE_ARRAY_ENC(3, 1, 8),
559 /* Array_B */ /* [3] */
560 BTF_TYPE_ARRAY_ENC(2, 1, 8),
561
562 BTF_END_RAW,
563 },
564 .str_sec = "",
565 .str_sec_size = sizeof(""),
566 .map_type = BPF_MAP_TYPE_ARRAY,
567 .map_name = "loop_test3_map",
568 .key_size = sizeof(int),
569 .value_size = sizeof(sizeof(int) * 8),
570 .key_id = 1,
571 .value_id = 2,
572 .max_entries = 4,
573 .btf_load_err = true,
574},
575
576/* typedef is _between_ the BTF type of Array_A and Array_B
577 *
578 * typedef Array_B int_array;
579 *
580 * Array_A <------------------+
581 * elem_type == int_array |
582 * | |
583 * | |
584 * Array_B <-------- + |
585 * elem_type == Array_A --+
586 */
587{
588 .descr = "loop test #4",
589 .raw_types = {
590 /* int */ /* [1] */
591 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
592 /* Array_A */ /* [2] */
593 BTF_TYPE_ARRAY_ENC(3, 1, 8),
594 /* typedef Array_B int_array */ /* [3] */
595 BTF_TYPEDEF_ENC(NAME_TBD, 4),
596 /* Array_B */ /* [4] */
597 BTF_TYPE_ARRAY_ENC(2, 1, 8),
598 BTF_END_RAW,
599 },
600 .str_sec = "\0int_array\0",
601 .str_sec_size = sizeof("\0int_array"),
602 .map_type = BPF_MAP_TYPE_ARRAY,
603 .map_name = "loop_test4_map",
604 .key_size = sizeof(int),
605 .value_size = sizeof(sizeof(int) * 8),
606 .key_id = 1,
607 .value_id = 2,
608 .max_entries = 4,
609 .btf_load_err = true,
610},
611
612/* typedef struct B Struct_B
613 *
614 * struct A {
615 * int x;
616 * Struct_B y;
617 * };
618 *
619 * struct B {
620 * int x;
621 * struct A y;
622 * };
623 */
624{
625 .descr = "loop test #5",
626 .raw_types = {
627 /* int */
628 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
629 /* struct A */ /* [2] */
630 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
631 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int x; */
632 BTF_MEMBER_ENC(NAME_TBD, 3, 32),/* Struct_B y; */
633 /* typedef struct B Struct_B */
634 BTF_TYPEDEF_ENC(NAME_TBD, 4), /* [3] */
635 /* struct B */ /* [4] */
636 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
637 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int x; */
638 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* struct A y; */
639 BTF_END_RAW,
640 },
641 .str_sec = "\0A\0x\0y\0Struct_B\0B\0x\0y",
642 .str_sec_size = sizeof("\0A\0x\0y\0Struct_B\0B\0x\0y"),
643 .map_type = BPF_MAP_TYPE_ARRAY,
644 .map_name = "loop_test5_map",
645 .key_size = sizeof(int),
646 .value_size = 8,
647 .key_id = 1,
648 .value_id = 2,
649 .max_entries = 4,
650 .btf_load_err = true,
651},
652
653/* struct A {
654 * int x;
655 * struct A array_a[4];
656 * };
657 */
658{
659 .descr = "loop test #6",
660 .raw_types = {
661 /* int */
662 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4), /* [1] */
663 BTF_TYPE_ARRAY_ENC(3, 1, 4), /* [2] */
664 /* struct A */ /* [3] */
665 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 2), 8),
666 BTF_MEMBER_ENC(NAME_TBD, 1, 0), /* int x; */
667 BTF_MEMBER_ENC(NAME_TBD, 2, 32),/* struct A array_a[4]; */
668 BTF_END_RAW,
669 },
670 .str_sec = "\0A\0x\0y",
671 .str_sec_size = sizeof("\0A\0x\0y"),
672 .map_type = BPF_MAP_TYPE_ARRAY,
673 .map_name = "loop_test6_map",
674 .key_size = sizeof(int),
675 .value_size = 8,
676 .key_id = 1,
677 .value_id = 2,
678 .max_entries = 4,
679 .btf_load_err = true,
680},
681
682{
683 .descr = "loop test #7",
684 .raw_types = {
685 /* int */ /* [1] */
686 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
687 /* struct A { */ /* [2] */
688 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), sizeof(void *)),
689 /* const void *m; */
690 BTF_MEMBER_ENC(NAME_TBD, 3, 0),
691 /* CONST type_id=3 */ /* [3] */
692 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 4),
693 /* PTR type_id=2 */ /* [4] */
694 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 3),
695 BTF_END_RAW,
696 },
697 .str_sec = "\0A\0m",
698 .str_sec_size = sizeof("\0A\0m"),
699 .map_type = BPF_MAP_TYPE_ARRAY,
700 .map_name = "loop_test7_map",
701 .key_size = sizeof(int),
702 .value_size = sizeof(void *),
703 .key_id = 1,
704 .value_id = 2,
705 .max_entries = 4,
706 .btf_load_err = true,
707},
708
709{
710 .descr = "loop test #8",
711 .raw_types = {
712 /* int */ /* [1] */
713 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
714 /* struct A { */ /* [2] */
715 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), sizeof(void *)),
716 /* const void *m; */
717 BTF_MEMBER_ENC(NAME_TBD, 4, 0),
718 /* struct B { */ /* [3] */
719 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 1), sizeof(void *)),
720 /* const void *n; */
721 BTF_MEMBER_ENC(NAME_TBD, 6, 0),
722 /* CONST type_id=5 */ /* [4] */
723 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 5),
724 /* PTR type_id=6 */ /* [5] */
725 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 6),
726 /* CONST type_id=7 */ /* [6] */
727 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_CONST, 0, 0), 7),
728 /* PTR type_id=4 */ /* [7] */
729 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_PTR, 0, 0), 4),
730 BTF_END_RAW,
731 },
732 .str_sec = "\0A\0m\0B\0n",
733 .str_sec_size = sizeof("\0A\0m\0B\0n"),
734 .map_type = BPF_MAP_TYPE_ARRAY,
735 .map_name = "loop_test8_map",
736 .key_size = sizeof(int),
737 .value_size = sizeof(void *),
738 .key_id = 1,
739 .value_id = 2,
740 .max_entries = 4,
741 .btf_load_err = true,
742},
743
744{
745 .descr = "type_off == str_off",
746 .raw_types = {
747 /* int */ /* [1] */
748 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
749 BTF_END_RAW,
750 },
751 .str_sec = "\0int",
752 .str_sec_size = sizeof("\0int"),
753 .map_type = BPF_MAP_TYPE_ARRAY,
754 .map_name = "hdr_test_map",
755 .key_size = sizeof(int),
756 .value_size = sizeof(int),
757 .key_id = 1,
758 .value_id = 1,
759 .max_entries = 4,
760 .btf_load_err = true,
761 .type_off_delta = sizeof(struct btf_type) + sizeof(int) + sizeof("\0int"),
762},
763
764{
765 .descr = "Unaligned type_off",
766 .raw_types = {
767 /* int */ /* [1] */
768 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
769 BTF_END_RAW,
770 },
771 .str_sec = "\0int",
772 .str_sec_size = sizeof("\0int"),
773 .map_type = BPF_MAP_TYPE_ARRAY,
774 .map_name = "hdr_test_map",
775 .key_size = sizeof(int),
776 .value_size = sizeof(int),
777 .key_id = 1,
778 .value_id = 1,
779 .max_entries = 4,
780 .btf_load_err = true,
781 .type_off_delta = 1,
782},
783
784{
785 .descr = "str_off beyonds btf size",
786 .raw_types = {
787 /* int */ /* [1] */
788 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
789 BTF_END_RAW,
790 },
791 .str_sec = "\0int",
792 .str_sec_size = sizeof("\0int"),
793 .map_type = BPF_MAP_TYPE_ARRAY,
794 .map_name = "hdr_test_map",
795 .key_size = sizeof(int),
796 .value_size = sizeof(int),
797 .key_id = 1,
798 .value_id = 1,
799 .max_entries = 4,
800 .btf_load_err = true,
801 .str_off_delta = sizeof("\0int") + 1,
802},
803
804{
805 .descr = "str_len beyonds btf size",
806 .raw_types = {
807 /* int */ /* [1] */
808 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
809 BTF_END_RAW,
810 },
811 .str_sec = "\0int",
812 .str_sec_size = sizeof("\0int"),
813 .map_type = BPF_MAP_TYPE_ARRAY,
814 .map_name = "hdr_test_map",
815 .key_size = sizeof(int),
816 .value_size = sizeof(int),
817 .key_id = 1,
818 .value_id = 1,
819 .max_entries = 4,
820 .btf_load_err = true,
821 .str_len_delta = 1,
822},
823
824{
825 .descr = "String section does not end with null",
826 .raw_types = {
827 /* int */ /* [1] */
828 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
829 BTF_END_RAW,
830 },
831 .str_sec = "\0int",
832 .str_sec_size = sizeof("\0int"),
833 .map_type = BPF_MAP_TYPE_ARRAY,
834 .map_name = "hdr_test_map",
835 .key_size = sizeof(int),
836 .value_size = sizeof(int),
837 .key_id = 1,
838 .value_id = 1,
839 .max_entries = 4,
840 .btf_load_err = true,
841 .str_len_delta = -1,
842},
843
844{
845 .descr = "Empty string section",
846 .raw_types = {
847 /* int */ /* [1] */
848 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
849 BTF_END_RAW,
850 },
851 .str_sec = "\0int",
852 .str_sec_size = sizeof("\0int"),
853 .map_type = BPF_MAP_TYPE_ARRAY,
854 .map_name = "hdr_test_map",
855 .key_size = sizeof(int),
856 .value_size = sizeof(int),
857 .key_id = 1,
858 .value_id = 1,
859 .max_entries = 4,
860 .btf_load_err = true,
861 .str_len_delta = 0 - (int)sizeof("\0int"),
862},
863
864}; /* struct btf_raw_test raw_tests[] */
865
866static const char *get_next_str(const char *start, const char *end)
867{
868 return start < end - 1 ? start + 1 : NULL;
869}
870
871static int get_type_sec_size(const __u32 *raw_types)
872{
873 int i;
874
875 for (i = MAX_NR_RAW_TYPES - 1;
876 i >= 0 && raw_types[i] != BTF_END_RAW;
877 i--)
878 ;
879
880 return i < 0 ? i : i * sizeof(raw_types[0]);
881}
882
883static void *btf_raw_create(const struct btf_header *hdr,
884 const __u32 *raw_types,
885 const char *str,
886 unsigned int str_sec_size,
887 unsigned int *btf_size)
888{
889 const char *next_str = str, *end_str = str + str_sec_size;
890 unsigned int size_needed, offset;
891 struct btf_header *ret_hdr;
892 int i, type_sec_size;
893 uint32_t *ret_types;
894 void *raw_btf;
895
896 type_sec_size = get_type_sec_size(raw_types);
897 if (type_sec_size < 0) {
898 fprintf(stderr, "Cannot get nr_raw_types\n");
899 return NULL;
900 }
901
902 size_needed = sizeof(*hdr) + type_sec_size + str_sec_size;
903 raw_btf = malloc(size_needed);
904 if (!raw_btf) {
905 fprintf(stderr, "Cannot allocate memory for raw_btf\n");
906 return NULL;
907 }
908
909 /* Copy header */
910 memcpy(raw_btf, hdr, sizeof(*hdr));
911 offset = sizeof(*hdr);
912
913 /* Copy type section */
914 ret_types = raw_btf + offset;
915 for (i = 0; i < type_sec_size / sizeof(raw_types[0]); i++) {
916 if (raw_types[i] == NAME_TBD) {
917 next_str = get_next_str(next_str, end_str);
918 if (!next_str) {
919 fprintf(stderr, "Error in getting next_str\n");
920 free(raw_btf);
921 return NULL;
922 }
923 ret_types[i] = next_str - str;
924 next_str += strlen(next_str);
925 } else {
926 ret_types[i] = raw_types[i];
927 }
928 }
929 offset += type_sec_size;
930
931 /* Copy string section */
932 memcpy(raw_btf + offset, str, str_sec_size);
933
934 ret_hdr = (struct btf_header *)raw_btf;
935 ret_hdr->str_off = type_sec_size;
936 ret_hdr->str_len = str_sec_size;
937
938 *btf_size = size_needed;
939
940 return raw_btf;
941}
942
943static int do_test_raw(unsigned int test_num)
944{
945 struct btf_raw_test *test = &raw_tests[test_num - 1];
946 struct bpf_create_map_attr create_attr = {};
947 int map_fd = -1, btf_fd = -1;
948 unsigned int raw_btf_size;
949 struct btf_header *hdr;
950 void *raw_btf;
951 int err;
952
953 fprintf(stderr, "BTF raw test[%u] (%s): ", test_num, test->descr);
954 raw_btf = btf_raw_create(&hdr_tmpl,
955 test->raw_types,
956 test->str_sec,
957 test->str_sec_size,
958 &raw_btf_size);
959
960 if (!raw_btf)
961 return -1;
962
963 hdr = raw_btf;
964
965 hdr->type_off = (int)hdr->type_off + test->type_off_delta;
966 hdr->str_off = (int)hdr->str_off + test->str_off_delta;
967 hdr->str_len = (int)hdr->str_len + test->str_len_delta;
968
969 *btf_log_buf = '\0';
970 btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
971 btf_log_buf, BTF_LOG_BUF_SIZE,
972 args.always_log);
973 free(raw_btf);
974
975 err = ((btf_fd == -1) != test->btf_load_err);
976 if (err)
977 fprintf(stderr, "btf_load_err:%d btf_fd:%d\n",
978 test->btf_load_err, btf_fd);
979
980 if (err || btf_fd == -1)
981 goto done;
982
983 create_attr.name = test->map_name;
984 create_attr.map_type = test->map_type;
985 create_attr.key_size = test->key_size;
986 create_attr.value_size = test->value_size;
987 create_attr.max_entries = test->max_entries;
988 create_attr.btf_fd = btf_fd;
989 create_attr.btf_key_id = test->key_id;
990 create_attr.btf_value_id = test->value_id;
991
992 map_fd = bpf_create_map_xattr(&create_attr);
993
994 err = ((map_fd == -1) != test->map_create_err);
995 if (err)
996 fprintf(stderr, "map_create_err:%d map_fd:%d\n",
997 test->map_create_err, map_fd);
998
999done:
1000 if (!err)
1001 fprintf(stderr, "OK\n");
1002
1003 if (*btf_log_buf && (err || args.always_log))
1004 fprintf(stderr, "%s\n", btf_log_buf);
1005
1006 if (btf_fd != -1)
1007 close(btf_fd);
1008 if (map_fd != -1)
1009 close(map_fd);
1010
1011 return err;
1012}
1013
1014static int test_raw(void)
1015{
1016 unsigned int i;
1017 int err = 0;
1018
1019 if (args.raw_test_num)
1020 return do_test_raw(args.raw_test_num);
1021
1022 for (i = 1; i <= ARRAY_SIZE(raw_tests); i++)
1023 err |= do_test_raw(i);
1024
1025 return err;
1026}
1027
1028struct btf_get_info_test {
1029 const char *descr;
1030 const char *str_sec;
1031 __u32 raw_types[MAX_NR_RAW_TYPES];
1032 __u32 str_sec_size;
1033 int info_size_delta;
1034};
1035
1036const struct btf_get_info_test get_info_tests[] = {
1037{
1038 .descr = "== raw_btf_size+1",
1039 .raw_types = {
1040 /* int */ /* [1] */
1041 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
1042 BTF_END_RAW,
1043 },
1044 .str_sec = "",
1045 .str_sec_size = sizeof(""),
1046 .info_size_delta = 1,
1047},
1048{
1049 .descr = "== raw_btf_size-3",
1050 .raw_types = {
1051 /* int */ /* [1] */
1052 BTF_TYPE_INT_ENC(0, BTF_INT_SIGNED, 0, 32, 4),
1053 BTF_END_RAW,
1054 },
1055 .str_sec = "",
1056 .str_sec_size = sizeof(""),
1057 .info_size_delta = -3,
1058},
1059};
1060
1061static int do_test_get_info(unsigned int test_num)
1062{
1063 const struct btf_get_info_test *test = &get_info_tests[test_num - 1];
1064 unsigned int raw_btf_size, user_btf_size, expected_nbytes;
1065 uint8_t *raw_btf = NULL, *user_btf = NULL;
1066 int btf_fd = -1, err;
1067
1068 fprintf(stderr, "BTF GET_INFO_BY_ID test[%u] (%s): ",
1069 test_num, test->descr);
1070
1071 raw_btf = btf_raw_create(&hdr_tmpl,
1072 test->raw_types,
1073 test->str_sec,
1074 test->str_sec_size,
1075 &raw_btf_size);
1076
1077 if (!raw_btf)
1078 return -1;
1079
1080 *btf_log_buf = '\0';
1081
1082 user_btf = malloc(raw_btf_size);
1083 if (!user_btf) {
1084 fprintf(stderr, "Cannot allocate memory for user_btf\n");
1085 err = -1;
1086 goto done;
1087 }
1088
1089 btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
1090 btf_log_buf, BTF_LOG_BUF_SIZE,
1091 args.always_log);
1092 if (btf_fd == -1) {
1093 fprintf(stderr, "bpf_load_btf:%s(%d)\n",
1094 strerror(errno), errno);
1095 err = -1;
1096 goto done;
1097 }
1098
1099 user_btf_size = (int)raw_btf_size + test->info_size_delta;
1100 expected_nbytes = min(raw_btf_size, user_btf_size);
1101 if (raw_btf_size > expected_nbytes)
1102 memset(user_btf + expected_nbytes, 0xff,
1103 raw_btf_size - expected_nbytes);
1104
1105 err = bpf_obj_get_info_by_fd(btf_fd, user_btf, &user_btf_size);
1106 if (err || user_btf_size != raw_btf_size ||
1107 memcmp(raw_btf, user_btf, expected_nbytes)) {
1108 fprintf(stderr,
1109 "err:%d(errno:%d) raw_btf_size:%u user_btf_size:%u expected_nbytes:%u memcmp:%d\n",
1110 err, errno,
1111 raw_btf_size, user_btf_size, expected_nbytes,
1112 memcmp(raw_btf, user_btf, expected_nbytes));
1113 err = -1;
1114 goto done;
1115 }
1116
1117 while (expected_nbytes < raw_btf_size) {
1118 fprintf(stderr, "%u...", expected_nbytes);
1119 if (user_btf[expected_nbytes++] != 0xff) {
1120 fprintf(stderr, "!= 0xff\n");
1121 err = -1;
1122 goto done;
1123 }
1124 }
1125
1126 fprintf(stderr, "OK\n");
1127
1128done:
1129 if (*btf_log_buf && (err || args.always_log))
1130 fprintf(stderr, "%s\n", btf_log_buf);
1131
1132 free(raw_btf);
1133 free(user_btf);
1134
1135 if (btf_fd != -1)
1136 close(btf_fd);
1137
1138 return err;
1139}
1140
1141static int test_get_info(void)
1142{
1143 unsigned int i;
1144 int err = 0;
1145
1146 if (args.get_info_test_num)
1147 return do_test_get_info(args.get_info_test_num);
1148
1149 for (i = 1; i <= ARRAY_SIZE(get_info_tests); i++)
1150 err |= do_test_get_info(i);
1151
1152 return err;
1153}
1154
1155struct btf_file_test {
1156 const char *file;
1157 bool btf_kv_notfound;
1158};
1159
1160static struct btf_file_test file_tests[] = {
1161{
1162 .file = "test_btf_haskv.o",
1163},
1164{
1165 .file = "test_btf_nokv.o",
1166 .btf_kv_notfound = true,
1167},
1168};
1169
1170static int file_has_btf_elf(const char *fn)
1171{
1172 Elf_Scn *scn = NULL;
1173 GElf_Ehdr ehdr;
1174 int elf_fd;
1175 Elf *elf;
1176 int ret;
1177
1178 if (elf_version(EV_CURRENT) == EV_NONE) {
1179 fprintf(stderr, "Failed to init libelf\n");
1180 return -1;
1181 }
1182
1183 elf_fd = open(fn, O_RDONLY);
1184 if (elf_fd == -1) {
1185 fprintf(stderr, "Cannot open file %s: %s(%d)\n",
1186 fn, strerror(errno), errno);
1187 return -1;
1188 }
1189
1190 elf = elf_begin(elf_fd, ELF_C_READ, NULL);
1191 if (!elf) {
1192 fprintf(stderr, "Failed to read ELF from %s. %s\n", fn,
1193 elf_errmsg(elf_errno()));
1194 ret = -1;
1195 goto done;
1196 }
1197
1198 if (!gelf_getehdr(elf, &ehdr)) {
1199 fprintf(stderr, "Failed to get EHDR from %s\n", fn);
1200 ret = -1;
1201 goto done;
1202 }
1203
1204 while ((scn = elf_nextscn(elf, scn))) {
1205 const char *sh_name;
1206 GElf_Shdr sh;
1207
1208 if (gelf_getshdr(scn, &sh) != &sh) {
1209 fprintf(stderr,
1210 "Failed to get section header from %s\n", fn);
1211 ret = -1;
1212 goto done;
1213 }
1214
1215 sh_name = elf_strptr(elf, ehdr.e_shstrndx, sh.sh_name);
1216 if (!strcmp(sh_name, BTF_ELF_SEC)) {
1217 ret = 1;
1218 goto done;
1219 }
1220 }
1221
1222 ret = 0;
1223
1224done:
1225 close(elf_fd);
1226 elf_end(elf);
1227 return ret;
1228}
1229
1230static int do_test_file(unsigned int test_num)
1231{
1232 const struct btf_file_test *test = &file_tests[test_num - 1];
1233 struct bpf_object *obj = NULL;
1234 struct bpf_program *prog;
1235 struct bpf_map *map;
1236 int err;
1237
1238 fprintf(stderr, "BTF libbpf test[%u] (%s): ", test_num,
1239 test->file);
1240
1241 err = file_has_btf_elf(test->file);
1242 if (err == -1)
1243 return err;
1244
1245 if (err == 0) {
1246 fprintf(stderr, "SKIP. No ELF %s found\n", BTF_ELF_SEC);
1247 return 0;
1248 }
1249
1250 obj = bpf_object__open(test->file);
1251 if (IS_ERR(obj))
1252 return PTR_ERR(obj);
1253
1254 err = bpf_object__btf_fd(obj);
1255 if (err == -1) {
1256 fprintf(stderr, "bpf_object__btf_fd: -1\n");
1257 goto done;
1258 }
1259
1260 prog = bpf_program__next(NULL, obj);
1261 if (!prog) {
1262 fprintf(stderr, "Cannot find bpf_prog\n");
1263 err = -1;
1264 goto done;
1265 }
1266
1267 bpf_program__set_type(prog, BPF_PROG_TYPE_TRACEPOINT);
1268 err = bpf_object__load(obj);
1269 if (err < 0) {
1270 fprintf(stderr, "bpf_object__load: %d\n", err);
1271 goto done;
1272 }
1273
1274 map = bpf_object__find_map_by_name(obj, "btf_map");
1275 if (!map) {
1276 fprintf(stderr, "btf_map not found\n");
1277 err = -1;
1278 goto done;
1279 }
1280
1281 err = (bpf_map__btf_key_id(map) == 0 || bpf_map__btf_value_id(map) == 0)
1282 != test->btf_kv_notfound;
1283 if (err) {
1284 fprintf(stderr,
1285 "btf_kv_notfound:%u btf_key_id:%u btf_value_id:%u\n",
1286 test->btf_kv_notfound,
1287 bpf_map__btf_key_id(map),
1288 bpf_map__btf_value_id(map));
1289 goto done;
1290 }
1291
1292 fprintf(stderr, "OK\n");
1293
1294done:
1295 bpf_object__close(obj);
1296 return err;
1297}
1298
1299static int test_file(void)
1300{
1301 unsigned int i;
1302 int err = 0;
1303
1304 if (args.file_test_num)
1305 return do_test_file(args.file_test_num);
1306
1307 for (i = 1; i <= ARRAY_SIZE(file_tests); i++)
1308 err |= do_test_file(i);
1309
1310 return err;
1311}
1312
1313const char *pprint_enum_str[] = {
1314 "ENUM_ZERO",
1315 "ENUM_ONE",
1316 "ENUM_TWO",
1317 "ENUM_THREE",
1318};
1319
1320struct pprint_mapv {
1321 uint32_t ui32;
1322 uint16_t ui16;
1323 /* 2 bytes hole */
1324 int32_t si32;
1325 uint32_t unused_bits2a:2,
1326 bits28:28,
1327 unused_bits2b:2;
1328 union {
1329 uint64_t ui64;
1330 uint8_t ui8a[8];
1331 };
1332 enum {
1333 ENUM_ZERO,
1334 ENUM_ONE,
1335 ENUM_TWO,
1336 ENUM_THREE,
1337 } aenum;
1338};
1339
1340static struct btf_raw_test pprint_test = {
1341 .descr = "BTF pretty print test #1",
1342 .raw_types = {
1343 /* unsighed char */ /* [1] */
1344 BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 8, 1),
1345 /* unsigned short */ /* [2] */
1346 BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 16, 2),
1347 /* unsigned int */ /* [3] */
1348 BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 32, 4),
1349 /* int */ /* [4] */
1350 BTF_TYPE_INT_ENC(NAME_TBD, BTF_INT_SIGNED, 0, 32, 4),
1351 /* unsigned long long */ /* [5] */
1352 BTF_TYPE_INT_ENC(NAME_TBD, 0, 0, 64, 8),
1353 /* 2 bits */ /* [6] */
1354 BTF_TYPE_INT_ENC(0, 0, 0, 2, 2),
1355 /* 28 bits */ /* [7] */
1356 BTF_TYPE_INT_ENC(0, 0, 0, 28, 4),
1357 /* uint8_t[8] */ /* [8] */
1358 BTF_TYPE_ARRAY_ENC(9, 3, 8),
1359 /* typedef unsigned char uint8_t */ /* [9] */
1360 BTF_TYPEDEF_ENC(NAME_TBD, 1),
1361 /* typedef unsigned short uint16_t */ /* [10] */
1362 BTF_TYPEDEF_ENC(NAME_TBD, 2),
1363 /* typedef unsigned int uint32_t */ /* [11] */
1364 BTF_TYPEDEF_ENC(NAME_TBD, 3),
1365 /* typedef int int32_t */ /* [12] */
1366 BTF_TYPEDEF_ENC(NAME_TBD, 4),
1367 /* typedef unsigned long long uint64_t *//* [13] */
1368 BTF_TYPEDEF_ENC(NAME_TBD, 5),
1369 /* union (anon) */ /* [14] */
1370 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_UNION, 0, 2), 8),
1371 BTF_MEMBER_ENC(NAME_TBD, 13, 0),/* uint64_t ui64; */
1372 BTF_MEMBER_ENC(NAME_TBD, 8, 0), /* uint8_t ui8a[8]; */
1373 /* enum (anon) */ /* [15] */
1374 BTF_TYPE_ENC(0, BTF_INFO_ENC(BTF_KIND_ENUM, 0, 4), 4),
1375 BTF_ENUM_ENC(NAME_TBD, 0),
1376 BTF_ENUM_ENC(NAME_TBD, 1),
1377 BTF_ENUM_ENC(NAME_TBD, 2),
1378 BTF_ENUM_ENC(NAME_TBD, 3),
1379 /* struct pprint_mapv */ /* [16] */
1380 BTF_TYPE_ENC(NAME_TBD, BTF_INFO_ENC(BTF_KIND_STRUCT, 0, 8), 28),
1381 BTF_MEMBER_ENC(NAME_TBD, 11, 0), /* uint32_t ui32 */
1382 BTF_MEMBER_ENC(NAME_TBD, 10, 32), /* uint16_t ui16 */
1383 BTF_MEMBER_ENC(NAME_TBD, 12, 64), /* int32_t si32 */
1384 BTF_MEMBER_ENC(NAME_TBD, 6, 96), /* unused_bits2a */
1385 BTF_MEMBER_ENC(NAME_TBD, 7, 98), /* bits28 */
1386 BTF_MEMBER_ENC(NAME_TBD, 6, 126), /* unused_bits2b */
1387 BTF_MEMBER_ENC(0, 14, 128), /* union (anon) */
1388 BTF_MEMBER_ENC(NAME_TBD, 15, 192), /* aenum */
1389 BTF_END_RAW,
1390 },
1391 .str_sec = "\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum",
1392 .str_sec_size = sizeof("\0unsigned char\0unsigned short\0unsigned int\0int\0unsigned long long\0uint8_t\0uint16_t\0uint32_t\0int32_t\0uint64_t\0ui64\0ui8a\0ENUM_ZERO\0ENUM_ONE\0ENUM_TWO\0ENUM_THREE\0pprint_mapv\0ui32\0ui16\0si32\0unused_bits2a\0bits28\0unused_bits2b\0aenum"),
1393 .map_type = BPF_MAP_TYPE_ARRAY,
1394 .map_name = "pprint_test",
1395 .key_size = sizeof(unsigned int),
1396 .value_size = sizeof(struct pprint_mapv),
1397 .key_id = 3, /* unsigned int */
1398 .value_id = 16, /* struct pprint_mapv */
1399 .max_entries = 128 * 1024,
1400};
1401
1402static void set_pprint_mapv(struct pprint_mapv *v, uint32_t i)
1403{
1404 v->ui32 = i;
1405 v->si32 = -i;
1406 v->unused_bits2a = 3;
1407 v->bits28 = i;
1408 v->unused_bits2b = 3;
1409 v->ui64 = i;
1410 v->aenum = i & 0x03;
1411}
1412
1413static int test_pprint(void)
1414{
1415 const struct btf_raw_test *test = &pprint_test;
1416 struct bpf_create_map_attr create_attr = {};
1417 int map_fd = -1, btf_fd = -1;
1418 struct pprint_mapv mapv = {};
1419 unsigned int raw_btf_size;
1420 char expected_line[255];
1421 FILE *pin_file = NULL;
1422 char pin_path[255];
1423 size_t line_len = 0;
1424 char *line = NULL;
1425 unsigned int key;
1426 uint8_t *raw_btf;
1427 ssize_t nread;
1428 int err;
1429
1430 fprintf(stderr, "%s......", test->descr);
1431 raw_btf = btf_raw_create(&hdr_tmpl, test->raw_types,
1432 test->str_sec, test->str_sec_size,
1433 &raw_btf_size);
1434
1435 if (!raw_btf)
1436 return -1;
1437
1438 *btf_log_buf = '\0';
1439 btf_fd = bpf_load_btf(raw_btf, raw_btf_size,
1440 btf_log_buf, BTF_LOG_BUF_SIZE,
1441 args.always_log);
1442 free(raw_btf);
1443
1444 if (btf_fd == -1) {
1445 err = -1;
1446 fprintf(stderr, "bpf_load_btf: %s(%d)\n",
1447 strerror(errno), errno);
1448 goto done;
1449 }
1450
1451 create_attr.name = test->map_name;
1452 create_attr.map_type = test->map_type;
1453 create_attr.key_size = test->key_size;
1454 create_attr.value_size = test->value_size;
1455 create_attr.max_entries = test->max_entries;
1456 create_attr.btf_fd = btf_fd;
1457 create_attr.btf_key_id = test->key_id;
1458 create_attr.btf_value_id = test->value_id;
1459
1460 map_fd = bpf_create_map_xattr(&create_attr);
1461 if (map_fd == -1) {
1462 err = -1;
1463 fprintf(stderr, "bpf_creat_map_btf: %s(%d)\n",
1464 strerror(errno), errno);
1465 goto done;
1466 }
1467
1468 if (snprintf(pin_path, sizeof(pin_path), "%s/%s",
1469 "/sys/fs/bpf", test->map_name) == sizeof(pin_path)) {
1470 err = -1;
1471 fprintf(stderr, "pin_path is too long\n");
1472 goto done;
1473 }
1474
1475 err = bpf_obj_pin(map_fd, pin_path);
1476 if (err) {
1477 fprintf(stderr, "Cannot pin to %s. %s(%d).\n", pin_path,
1478 strerror(errno), errno);
1479 goto done;
1480 }
1481
1482 for (key = 0; key < test->max_entries; key++) {
1483 set_pprint_mapv(&mapv, key);
1484 bpf_map_update_elem(map_fd, &key, &mapv, 0);
1485 }
1486
1487 pin_file = fopen(pin_path, "r");
1488 if (!pin_file) {
1489 err = -1;
1490 fprintf(stderr, "fopen(%s): %s(%d)\n", pin_path,
1491 strerror(errno), errno);
1492 goto done;
1493 }
1494
1495 /* Skip lines start with '#' */
1496 while ((nread = getline(&line, &line_len, pin_file)) > 0 &&
1497 *line == '#')
1498 ;
1499
1500 if (nread <= 0) {
1501 err = -1;
1502 fprintf(stderr, "Unexpected EOF\n");
1503 goto done;
1504 }
1505
1506 key = 0;
1507 do {
1508 ssize_t nexpected_line;
1509
1510 set_pprint_mapv(&mapv, key);
1511 nexpected_line = snprintf(expected_line, sizeof(expected_line),
1512 "%u: {%u,0,%d,0x%x,0x%x,0x%x,{%lu|[%u,%u,%u,%u,%u,%u,%u,%u]},%s}\n",
1513 key,
1514 mapv.ui32, mapv.si32,
1515 mapv.unused_bits2a, mapv.bits28, mapv.unused_bits2b,
1516 mapv.ui64,
1517 mapv.ui8a[0], mapv.ui8a[1], mapv.ui8a[2], mapv.ui8a[3],
1518 mapv.ui8a[4], mapv.ui8a[5], mapv.ui8a[6], mapv.ui8a[7],
1519 pprint_enum_str[mapv.aenum]);
1520
1521 if (nexpected_line == sizeof(expected_line)) {
1522 err = -1;
1523 fprintf(stderr, "expected_line is too long\n");
1524 goto done;
1525 }
1526
1527 if (strcmp(expected_line, line)) {
1528 err = -1;
1529 fprintf(stderr, "unexpected pprint output\n");
1530 fprintf(stderr, "expected: %s", expected_line);
1531 fprintf(stderr, " read: %s", line);
1532 goto done;
1533 }
1534
1535 nread = getline(&line, &line_len, pin_file);
1536 } while (++key < test->max_entries && nread > 0);
1537
1538 if (key < test->max_entries) {
1539 err = -1;
1540 fprintf(stderr, "Unexpected EOF\n");
1541 goto done;
1542 }
1543
1544 if (nread > 0) {
1545 err = -1;
1546 fprintf(stderr, "Unexpected extra pprint output: %s\n", line);
1547 goto done;
1548 }
1549
1550 err = 0;
1551
1552done:
1553 if (!err)
1554 fprintf(stderr, "OK\n");
1555 if (*btf_log_buf && (err || args.always_log))
1556 fprintf(stderr, "%s\n", btf_log_buf);
1557 if (btf_fd != -1)
1558 close(btf_fd);
1559 if (map_fd != -1)
1560 close(map_fd);
1561 if (pin_file)
1562 fclose(pin_file);
1563 unlink(pin_path);
1564 free(line);
1565
1566 return err;
1567}
1568
1569static void usage(const char *cmd)
1570{
1571 fprintf(stderr, "Usage: %s [-l] [[-r test_num (1 - %zu)] | [-g test_num (1 - %zu)] | [-f test_num (1 - %zu)] | [-p]]\n",
1572 cmd, ARRAY_SIZE(raw_tests), ARRAY_SIZE(get_info_tests),
1573 ARRAY_SIZE(file_tests));
1574}
1575
1576static int parse_args(int argc, char **argv)
1577{
1578 const char *optstr = "lpf:r:g:";
1579 int opt;
1580
1581 while ((opt = getopt(argc, argv, optstr)) != -1) {
1582 switch (opt) {
1583 case 'l':
1584 args.always_log = true;
1585 break;
1586 case 'f':
1587 args.file_test_num = atoi(optarg);
1588 args.file_test = true;
1589 break;
1590 case 'r':
1591 args.raw_test_num = atoi(optarg);
1592 args.raw_test = true;
1593 break;
1594 case 'g':
1595 args.get_info_test_num = atoi(optarg);
1596 args.get_info_test = true;
1597 break;
1598 case 'p':
1599 args.pprint_test = true;
1600 break;
1601 case 'h':
1602 usage(argv[0]);
1603 exit(0);
1604 default:
1605 usage(argv[0]);
1606 return -1;
1607 }
1608 }
1609
1610 if (args.raw_test_num &&
1611 (args.raw_test_num < 1 ||
1612 args.raw_test_num > ARRAY_SIZE(raw_tests))) {
1613 fprintf(stderr, "BTF raw test number must be [1 - %zu]\n",
1614 ARRAY_SIZE(raw_tests));
1615 return -1;
1616 }
1617
1618 if (args.file_test_num &&
1619 (args.file_test_num < 1 ||
1620 args.file_test_num > ARRAY_SIZE(file_tests))) {
1621 fprintf(stderr, "BTF file test number must be [1 - %zu]\n",
1622 ARRAY_SIZE(file_tests));
1623 return -1;
1624 }
1625
1626 if (args.get_info_test_num &&
1627 (args.get_info_test_num < 1 ||
1628 args.get_info_test_num > ARRAY_SIZE(get_info_tests))) {
1629 fprintf(stderr, "BTF get info test number must be [1 - %zu]\n",
1630 ARRAY_SIZE(get_info_tests));
1631 return -1;
1632 }
1633
1634 return 0;
1635}
1636
1637int main(int argc, char **argv)
1638{
1639 int err = 0;
1640
1641 err = parse_args(argc, argv);
1642 if (err)
1643 return err;
1644
1645 if (args.always_log)
1646 libbpf_set_print(__base_pr, __base_pr, __base_pr);
1647
1648 if (args.raw_test)
1649 err |= test_raw();
1650
1651 if (args.get_info_test)
1652 err |= test_get_info();
1653
1654 if (args.file_test)
1655 err |= test_file();
1656
1657 if (args.pprint_test)
1658 err |= test_pprint();
1659
1660 if (args.raw_test || args.get_info_test || args.file_test ||
1661 args.pprint_test)
1662 return err;
1663
1664 err |= test_raw();
1665 err |= test_get_info();
1666 err |= test_file();
1667
1668 return err;
1669}