162 lines · c
1// SPDX-License-Identifier: GPL-2.02/* 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 9struct 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 */41void 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}162