| // 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 <linux/bpf.h> | |
| #include <linux/btf.h> | |
| #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; | |
| } |