// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) /* Copyright (c) 2021 Facebook */ /* Copyright (c) 2024, Oracle and/or its affiliates. */ #ifdef __KERNEL__ #include #include #define btf_var_secinfos(t) (struct btf_var_secinfo *)btf_type_var_secinfo(t) #else #include "btf.h" #include "libbpf_internal.h" #endif int btf_field_iter_init(struct btf_field_iter *it, struct btf_type *t, enum btf_field_iter_kind iter_kind) { it->p = NULL; it->m_idx = -1; it->off_idx = 0; it->vlen = 0; switch (iter_kind) { case BTF_FIELD_ITER_IDS: switch (btf_kind(t)) { case BTF_KIND_UNKN: case BTF_KIND_INT: case BTF_KIND_FLOAT: case BTF_KIND_ENUM: case BTF_KIND_ENUM64: it->desc = (struct btf_field_desc) {}; break; case BTF_KIND_FWD: case BTF_KIND_CONST: case BTF_KIND_VOLATILE: case BTF_KIND_RESTRICT: case BTF_KIND_PTR: case BTF_KIND_TYPEDEF: case BTF_KIND_FUNC: case BTF_KIND_VAR: case BTF_KIND_DECL_TAG: case BTF_KIND_TYPE_TAG: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, type)} }; break; case BTF_KIND_ARRAY: it->desc = (struct btf_field_desc) { 2, {sizeof(struct btf_type) + offsetof(struct btf_array, type), sizeof(struct btf_type) + offsetof(struct btf_array, index_type)} }; break; case BTF_KIND_STRUCT: case BTF_KIND_UNION: it->desc = (struct btf_field_desc) { 0, {}, sizeof(struct btf_member), 1, {offsetof(struct btf_member, type)} }; break; case BTF_KIND_FUNC_PROTO: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, type)}, sizeof(struct btf_param), 1, {offsetof(struct btf_param, type)} }; break; case BTF_KIND_DATASEC: it->desc = (struct btf_field_desc) { 0, {}, sizeof(struct btf_var_secinfo), 1, {offsetof(struct btf_var_secinfo, type)} }; break; default: return -EINVAL; } break; case BTF_FIELD_ITER_STRS: switch (btf_kind(t)) { case BTF_KIND_UNKN: it->desc = (struct btf_field_desc) {}; break; case BTF_KIND_INT: case BTF_KIND_FLOAT: case BTF_KIND_FWD: case BTF_KIND_ARRAY: case BTF_KIND_CONST: case BTF_KIND_VOLATILE: case BTF_KIND_RESTRICT: case BTF_KIND_PTR: case BTF_KIND_TYPEDEF: case BTF_KIND_FUNC: case BTF_KIND_VAR: case BTF_KIND_DECL_TAG: case BTF_KIND_TYPE_TAG: case BTF_KIND_DATASEC: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, name_off)} }; break; case BTF_KIND_ENUM: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, name_off)}, sizeof(struct btf_enum), 1, {offsetof(struct btf_enum, name_off)} }; break; case BTF_KIND_ENUM64: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, name_off)}, sizeof(struct btf_enum64), 1, {offsetof(struct btf_enum64, name_off)} }; break; case BTF_KIND_STRUCT: case BTF_KIND_UNION: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, name_off)}, sizeof(struct btf_member), 1, {offsetof(struct btf_member, name_off)} }; break; case BTF_KIND_FUNC_PROTO: it->desc = (struct btf_field_desc) { 1, {offsetof(struct btf_type, name_off)}, sizeof(struct btf_param), 1, {offsetof(struct btf_param, name_off)} }; break; default: return -EINVAL; } break; default: return -EINVAL; } if (it->desc.m_sz) it->vlen = btf_vlen(t); it->p = t; return 0; } __u32 *btf_field_iter_next(struct btf_field_iter *it) { if (!it->p) return NULL; if (it->m_idx < 0) { if (it->off_idx < it->desc.t_off_cnt) return it->p + it->desc.t_offs[it->off_idx++]; /* move to per-member iteration */ it->m_idx = 0; it->p += sizeof(struct btf_type); it->off_idx = 0; } /* if type doesn't have members, stop */ if (it->desc.m_sz == 0) { it->p = NULL; return NULL; } if (it->off_idx >= it->desc.m_off_cnt) { /* exhausted this member's fields, go to the next member */ it->m_idx++; it->p += it->desc.m_sz; it->off_idx = 0; } if (it->m_idx < it->vlen) return it->p + it->desc.m_offs[it->off_idx++]; it->p = NULL; return NULL; }