Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/bpf: Add btf_field_iter selftests

The added selftests verify that for every BTF kind we iterate correctly
over consituent strings and ids.

Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20240605153314.3727466-1-alan.maguire@oracle.com

authored by

Alan Maguire and committed by
Daniel Borkmann
b24862ba 7015843a

+161
+161
tools/testing/selftests/bpf/prog_tests/btf_field_iter.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (c) 2024, Oracle and/or its affiliates. */ 3 + 4 + #include <test_progs.h> 5 + #include <bpf/btf.h> 6 + #include "btf_helpers.h" 7 + #include "bpf/libbpf_internal.h" 8 + 9 + struct field_data { 10 + __u32 ids[5]; 11 + const char *strs[5]; 12 + } fields[] = { 13 + { .ids = {}, .strs = {} }, 14 + { .ids = {}, .strs = { "int" } }, 15 + { .ids = {}, .strs = { "int64" } }, 16 + { .ids = { 1 }, .strs = { "" } }, 17 + { .ids = { 2, 1 }, .strs = { "" } }, 18 + { .ids = { 3, 1 }, .strs = { "s1", "f1", "f2" } }, 19 + { .ids = { 1, 5 }, .strs = { "u1", "f1", "f2" } }, 20 + { .ids = {}, .strs = { "e1", "v1", "v2" } }, 21 + { .ids = {}, .strs = { "fw1" } }, 22 + { .ids = { 1 }, .strs = { "t" } }, 23 + { .ids = { 2 }, .strs = { "" } }, 24 + { .ids = { 1 }, .strs = { "" } }, 25 + { .ids = { 3 }, .strs = { "" } }, 26 + { .ids = { 1, 1, 3 }, .strs = { "", "p1", "p2" } }, 27 + { .ids = { 13 }, .strs = { "func" } }, 28 + { .ids = { 1 }, .strs = { "var1" } }, 29 + { .ids = { 3 }, .strs = { "var2" } }, 30 + { .ids = {}, .strs = { "float" } }, 31 + { .ids = { 11 }, .strs = { "decltag" } }, 32 + { .ids = { 6 }, .strs = { "typetag" } }, 33 + { .ids = {}, .strs = { "e64", "eval1", "eval2", "eval3" } }, 34 + { .ids = { 15, 16 }, .strs = { "datasec1" } } 35 + 36 + }; 37 + 38 + /* Fabricate BTF with various types and check BTF field iteration finds types, 39 + * strings expected. 40 + */ 41 + void test_btf_field_iter(void) 42 + { 43 + struct btf *btf = NULL; 44 + int id; 45 + 46 + btf = btf__new_empty(); 47 + if (!ASSERT_OK_PTR(btf, "empty_btf")) 48 + return; 49 + 50 + btf__add_int(btf, "int", 4, BTF_INT_SIGNED); /* [1] int */ 51 + btf__add_int(btf, "int64", 8, BTF_INT_SIGNED); /* [2] int64 */ 52 + btf__add_ptr(btf, 1); /* [3] int * */ 53 + btf__add_array(btf, 1, 2, 3); /* [4] int64[3] */ 54 + btf__add_struct(btf, "s1", 12); /* [5] struct s1 { */ 55 + btf__add_field(btf, "f1", 3, 0, 0); /* int *f1; */ 56 + btf__add_field(btf, "f2", 1, 0, 0); /* int f2; */ 57 + /* } */ 58 + btf__add_union(btf, "u1", 12); /* [6] union u1 { */ 59 + btf__add_field(btf, "f1", 1, 0, 0); /* int f1; */ 60 + btf__add_field(btf, "f2", 5, 0, 0); /* struct s1 f2; */ 61 + /* } */ 62 + btf__add_enum(btf, "e1", 4); /* [7] enum e1 { */ 63 + btf__add_enum_value(btf, "v1", 1); /* v1 = 1; */ 64 + btf__add_enum_value(btf, "v2", 2); /* v2 = 2; */ 65 + /* } */ 66 + 67 + btf__add_fwd(btf, "fw1", BTF_FWD_STRUCT); /* [8] struct fw1; */ 68 + btf__add_typedef(btf, "t", 1); /* [9] typedef int t; */ 69 + btf__add_volatile(btf, 2); /* [10] volatile int64; */ 70 + btf__add_const(btf, 1); /* [11] const int; */ 71 + btf__add_restrict(btf, 3); /* [12] restrict int *; */ 72 + btf__add_func_proto(btf, 1); /* [13] int (*)(int p1, int *p2); */ 73 + btf__add_func_param(btf, "p1", 1); 74 + btf__add_func_param(btf, "p2", 3); 75 + 76 + btf__add_func(btf, "func", BTF_FUNC_GLOBAL, 13);/* [14] int func(int p1, int *p2); */ 77 + btf__add_var(btf, "var1", BTF_VAR_STATIC, 1); /* [15] static int var1; */ 78 + btf__add_var(btf, "var2", BTF_VAR_STATIC, 3); /* [16] static int *var2; */ 79 + btf__add_float(btf, "float", 4); /* [17] float; */ 80 + btf__add_decl_tag(btf, "decltag", 11, -1); /* [18] decltag const int; */ 81 + btf__add_type_tag(btf, "typetag", 6); /* [19] typetag union u1; */ 82 + btf__add_enum64(btf, "e64", 8, true); /* [20] enum { */ 83 + btf__add_enum64_value(btf, "eval1", 1000); /* eval1 = 1000, */ 84 + btf__add_enum64_value(btf, "eval2", 2000); /* eval2 = 2000, */ 85 + btf__add_enum64_value(btf, "eval3", 3000); /* eval3 = 3000 */ 86 + /* } */ 87 + btf__add_datasec(btf, "datasec1", 12); /* [21] datasec datasec1 */ 88 + btf__add_datasec_var_info(btf, 15, 0, 4); 89 + btf__add_datasec_var_info(btf, 16, 4, 8); 90 + 91 + VALIDATE_RAW_BTF( 92 + btf, 93 + "[1] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED", 94 + "[2] INT 'int64' size=8 bits_offset=0 nr_bits=64 encoding=SIGNED", 95 + "[3] PTR '(anon)' type_id=1", 96 + "[4] ARRAY '(anon)' type_id=2 index_type_id=1 nr_elems=3", 97 + "[5] STRUCT 's1' size=12 vlen=2\n" 98 + "\t'f1' type_id=3 bits_offset=0\n" 99 + "\t'f2' type_id=1 bits_offset=0", 100 + "[6] UNION 'u1' size=12 vlen=2\n" 101 + "\t'f1' type_id=1 bits_offset=0\n" 102 + "\t'f2' type_id=5 bits_offset=0", 103 + "[7] ENUM 'e1' encoding=UNSIGNED size=4 vlen=2\n" 104 + "\t'v1' val=1\n" 105 + "\t'v2' val=2", 106 + "[8] FWD 'fw1' fwd_kind=struct", 107 + "[9] TYPEDEF 't' type_id=1", 108 + "[10] VOLATILE '(anon)' type_id=2", 109 + "[11] CONST '(anon)' type_id=1", 110 + "[12] RESTRICT '(anon)' type_id=3", 111 + "[13] FUNC_PROTO '(anon)' ret_type_id=1 vlen=2\n" 112 + "\t'p1' type_id=1\n" 113 + "\t'p2' type_id=3", 114 + "[14] FUNC 'func' type_id=13 linkage=global", 115 + "[15] VAR 'var1' type_id=1, linkage=static", 116 + "[16] VAR 'var2' type_id=3, linkage=static", 117 + "[17] FLOAT 'float' size=4", 118 + "[18] DECL_TAG 'decltag' type_id=11 component_idx=-1", 119 + "[19] TYPE_TAG 'typetag' type_id=6", 120 + "[20] ENUM64 'e64' encoding=SIGNED size=8 vlen=3\n" 121 + "\t'eval1' val=1000\n" 122 + "\t'eval2' val=2000\n" 123 + "\t'eval3' val=3000", 124 + "[21] DATASEC 'datasec1' size=12 vlen=2\n" 125 + "\ttype_id=15 offset=0 size=4\n" 126 + "\ttype_id=16 offset=4 size=8"); 127 + 128 + for (id = 1; id < btf__type_cnt(btf); id++) { 129 + struct btf_type *t = btf_type_by_id(btf, id); 130 + struct btf_field_iter it_strs, it_ids; 131 + int str_idx = 0, id_idx = 0; 132 + __u32 *next_str, *next_id; 133 + 134 + if (!ASSERT_OK_PTR(t, "btf_type_by_id")) 135 + break; 136 + if (!ASSERT_OK(btf_field_iter_init(&it_strs, t, BTF_FIELD_ITER_STRS), 137 + "iter_init_strs")) 138 + break; 139 + if (!ASSERT_OK(btf_field_iter_init(&it_ids, t, BTF_FIELD_ITER_IDS), 140 + "iter_init_ids")) 141 + break; 142 + while ((next_str = btf_field_iter_next(&it_strs))) { 143 + const char *str = btf__str_by_offset(btf, *next_str); 144 + 145 + if (!ASSERT_OK(strcmp(fields[id].strs[str_idx], str), "field_str_match")) 146 + break; 147 + str_idx++; 148 + } 149 + /* ensure no more strings are expected */ 150 + ASSERT_EQ(fields[id].strs[str_idx], NULL, "field_str_cnt"); 151 + 152 + while ((next_id = btf_field_iter_next(&it_ids))) { 153 + if (!ASSERT_EQ(*next_id, fields[id].ids[id_idx], "field_id_match")) 154 + break; 155 + id_idx++; 156 + } 157 + /* ensure no more ids are expected */ 158 + ASSERT_EQ(fields[id].ids[id_idx], 0, "field_id_cnt"); 159 + } 160 + btf__free(btf); 161 + }