1 // SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) 2 /* Copyright (c) 2021 Facebook */ 3 /* Copyright (c) 2024, Oracle and/or its affiliates. */ 4 5 #ifdef __KERNEL__ 6 #include <linux/bpf.h> 7 #include <linux/btf.h> 8 9 #define btf_var_secinfos(t) (struct btf_var_secinfo *)btf_type_var_secinfo(t) 10 11 #else 12 #include "btf.h" 13 #include "libbpf_internal.h" 14 #endif 15 16 int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, 17 enum btf_field_iter_kind iter_kind) 18 { 19 it->p = NULL; 20 it->m_idx = -1; 21 it->off_idx = 0; 22 it->vlen = 0; 23 24 switch (iter_kind) { 25 case BTF_FIELD_ITER_IDS: 26 switch (btf_kind(t)) { 27 case BTF_KIND_UNKN: 28 case BTF_KIND_INT: 29 case BTF_KIND_FLOAT: 30 case BTF_KIND_ENUM: 31 case BTF_KIND_ENUM64: 32 it->desc = (struct btf_field_desc) {}; 33 break; 34 case BTF_KIND_FWD: 35 case BTF_KIND_CONST: 36 case BTF_KIND_VOLATILE: 37 case BTF_KIND_RESTRICT: 38 case BTF_KIND_PTR: 39 case BTF_KIND_TYPEDEF: 40 case BTF_KIND_FUNC: 41 case BTF_KIND_VAR: 42 case BTF_KIND_DECL_TAG: 43 case BTF_KIND_TYPE_TAG: 44 it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, type)} }; 45 break; 46 case BTF_KIND_ARRAY: 47 it->desc = (struct btf_field_desc) { 48 2, {sizeof(struct btf_type) + offsetof(struct btf_array, type), 49 sizeof(struct btf_type) + offsetof(struct btf_array, index_type)} 50 }; 51 break; 52 case BTF_KIND_STRUCT: 53 case BTF_KIND_UNION: 54 it->desc = (struct btf_field_desc) { 55 0, {}, 56 sizeof(struct btf_member), 57 1, {offsetof(struct btf_member, type)} 58 }; 59 break; 60 case BTF_KIND_FUNC_PROTO: 61 it->desc = (struct btf_field_desc) { 62 1, {offsetof(struct btf_type, type)}, 63 sizeof(struct btf_param), 64 1, {offsetof(struct btf_param, type)} 65 }; 66 break; 67 case BTF_KIND_DATASEC: 68 it->desc = (struct btf_field_desc) { 69 0, {}, 70 sizeof(struct btf_var_secinfo), 71 1, {offsetof(struct btf_var_secinfo, type)} 72 }; 73 break; 74 default: 75 return -EINVAL; 76 } 77 break; 78 case BTF_FIELD_ITER_STRS: 79 switch (btf_kind(t)) { 80 case BTF_KIND_UNKN: 81 it->desc = (struct btf_field_desc) {}; 82 break; 83 case BTF_KIND_INT: 84 case BTF_KIND_FLOAT: 85 case BTF_KIND_FWD: 86 case BTF_KIND_ARRAY: 87 case BTF_KIND_CONST: 88 case BTF_KIND_VOLATILE: 89 case BTF_KIND_RESTRICT: 90 case BTF_KIND_PTR: 91 case BTF_KIND_TYPEDEF: 92 case BTF_KIND_FUNC: 93 case BTF_KIND_VAR: 94 case BTF_KIND_DECL_TAG: 95 case BTF_KIND_TYPE_TAG: 96 case BTF_KIND_DATASEC: 97 it->desc = (struct btf_field_desc) { 98 1, {offsetof(struct btf_type, name_off)} 99 }; 100 break; 101 case BTF_KIND_ENUM: 102 it->desc = (struct btf_field_desc) { 103 1, {offsetof(struct btf_type, name_off)}, 104 sizeof(struct btf_enum), 105 1, {offsetof(struct btf_enum, name_off)} 106 }; 107 break; 108 case BTF_KIND_ENUM64: 109 it->desc = (struct btf_field_desc) { 110 1, {offsetof(struct btf_type, name_off)}, 111 sizeof(struct btf_enum64), 112 1, {offsetof(struct btf_enum64, name_off)} 113 }; 114 break; 115 case BTF_KIND_STRUCT: 116 case BTF_KIND_UNION: 117 it->desc = (struct btf_field_desc) { 118 1, {offsetof(struct btf_type, name_off)}, 119 sizeof(struct btf_member), 120 1, {offsetof(struct btf_member, name_off)} 121 }; 122 break; 123 case BTF_KIND_FUNC_PROTO: 124 it->desc = (struct btf_field_desc) { 125 1, {offsetof(struct btf_type, name_off)}, 126 sizeof(struct btf_param), 127 1, {offsetof(struct btf_param, name_off)} 128 }; 129 break; 130 default: 131 return -EINVAL; 132 } 133 break; 134 default: 135 return -EINVAL; 136 } 137 138 if (it->desc.m_sz) 139 it->vlen = btf_vlen(t); 140 141 it->p = t; 142 return 0; 143 } 144 145 __u32 *btf_field_iter_next(struct btf_field_iter *it) 146 { 147 if (!it->p) 148 return NULL; 149 150 if (it->m_idx < 0) { 151 if (it->off_idx < it->desc.t_off_cnt) 152 return it->p + it->desc.t_offs[it->off_idx++]; 153 /* move to per-member iteration */ 154 it->m_idx = 0; 155 it->p += sizeof(struct btf_type); 156 it->off_idx = 0; 157 } 158 159 /* if type doesn't have members, stop */ 160 if (it->desc.m_sz == 0) { 161 it->p = NULL; 162 return NULL; 163 } 164 165 if (it->off_idx >= it->desc.m_off_cnt) { 166 /* exhausted this member's fields, go to the next member */ 167 it->m_idx++; 168 it->p += it->desc.m_sz; 169 it->off_idx = 0; 170 } 171 172 if (it->m_idx < it->vlen) 173 return it->p + it->desc.m_offs[it->off_idx++]; 174 175 it->p = NULL; 176 return NULL; 177 } 178