/* Type handling functions. Copyright (C) 2019-2026 Free Software Foundation, Inc. This file is part of libctf. libctf is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not see <http://www.gnu.org/licenses/>. */ #include <ctf-impl.h>#include <assert.h>#include <string.h> /* Determine whether a type is a parent or a child. */ intctf_type_isparent (ctf_dict_t *fp, ctf_id_t id){ return (LCTF_TYPE_ISPARENT (fp, id));} intctf_type_ischild (ctf_dict_t * fp, ctf_id_t id){ return (LCTF_TYPE_ISCHILD (fp, id));} /* Expand a structure element into the passed-in ctf_lmember_t. */ static intctf_struct_member (ctf_dict_t *fp, ctf_lmember_t *dst, const ctf_type_t *tp, unsigned char *vlen, size_t vbytes, size_t n){ if (!ctf_assert (fp, n < LCTF_INFO_VLEN (fp, tp->ctt_info))) return -1; /* errno is set for us. */ /* Already large. */ if (tp->ctt_size >= CTF_LSTRUCT_THRESH) { ctf_lmember_t *lmp = (ctf_lmember_t *) vlen; if (!ctf_assert (fp, (n + 1) * sizeof (ctf_lmember_t) <= vbytes)) return -1; /* errno is set for us. */ memcpy (dst, &lmp[n], sizeof (ctf_lmember_t)); } else { ctf_member_t *mp = (ctf_member_t *) vlen; dst->ctlm_name = mp[n].ctm_name; dst->ctlm_type = mp[n].ctm_type; dst->ctlm_offsetlo = mp[n].ctm_offset; dst->ctlm_offsethi = 0; } return 0;} /* Iterate over the members of a STRUCT or UNION. We pass the name, member type, and offset of each member to the specified callback function. */ intctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg){ ctf_next_t *i = NULL; ssize_t offset; const char *name; ctf_id_t membtype; while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0) { int rc; if ((rc = func (name, membtype, offset, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0;} /* Iterate over the members of a STRUCT or UNION, returning each member's offset and optionally name and member type in turn. On end-of-iteration, returns -1. If FLAGS is CTF_MN_RECURSE, recurse into unnamed members. */ ssize_tctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, const char **name, ctf_id_t *membtype, int flags){ ctf_dict_t *ofp = fp; uint32_t kind; ssize_t offset; uint32_t max_vlen; ctf_next_t *i = *it; if (!i) { const ctf_type_t *tp; ctf_dtdef_t *dtd; ssize_t size; ssize_t increment; if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) return -1; /* errno is set for us. */ if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) return -1; /* errno is set for us. */ if ((i = ctf_next_create ()) == NULL) return ctf_set_errno (ofp, ENOMEM); i->cu.ctn_fp = ofp; i->ctn_tp = tp; ctf_get_ctt_size (fp, tp, &size, &increment); kind = LCTF_INFO_KIND (fp, tp->ctt_info); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) { ctf_next_destroy (i); return (ctf_set_errno (ofp, ECTF_NOTSOU)); } if ((dtd = ctf_dynamic_type (fp, type)) != NULL) { i->u.ctn_vlen = dtd->dtd_vlen; i->ctn_size = dtd->dtd_vlen_alloc; } else { unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); i->u.ctn_vlen = (unsigned char *) tp + increment; i->ctn_size = LCTF_VBYTES (fp, kind, size, vlen);; } i->ctn_iter_fun = (void (*) (void)) ctf_member_next; i->ctn_n = 0; *it = i; } if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun) return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN)); if (ofp != i->cu.ctn_fp) return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP)); /* Resolve to the native dict of this type. */ if ((fp = ctf_get_dict (ofp, type)) == NULL) return (ctf_set_errno (ofp, ECTF_NOPARENT)); max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info); /* When we hit an unnamed struct/union member, we set ctn_type to indicate that we are inside one, then return the unnamed member: on the next call, we must skip over top-level member iteration in favour of iteration within the sub-struct until it later turns out that that iteration has ended. */ retry: if (!i->ctn_type) { ctf_lmember_t memb; const char *membname; if (i->ctn_n == max_vlen) goto end_iter; if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size, i->ctn_n) < 0) return (ctf_set_errno (ofp, ctf_errno (fp))); membname = ctf_strptr (fp, memb.ctlm_name); if (name) *name = membname; if (membtype) *membtype = memb.ctlm_type; offset = (unsigned long) CTF_LMEM_OFFSET (&memb); if (membname[0] == 0) { ctf_id_t resolved; if ((resolved = ctf_type_resolve (fp, memb.ctlm_type)) == CTF_ERR) { if (ctf_errno (fp) != ECTF_NONREPRESENTABLE) return -1; /* errno is set for us. */ resolved = memb.ctlm_type; } if (ctf_type_kind (fp, resolved) == CTF_K_STRUCT || ctf_type_kind (fp, resolved) == CTF_K_UNION) i->ctn_type = resolved; } i->ctn_n++; /* The callers might want automatic recursive sub-struct traversal. */ if (!(flags & CTF_MN_RECURSE)) i->ctn_type = 0; /* Sub-struct traversal starting? Take note of the offset of this member, for later boosting of sub-struct members' offsets. */ if (i->ctn_type) i->ctn_increment = offset; } /* Traversing a sub-struct? Just return it, with the offset adjusted. */ else { ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name, membtype, flags); if (ret >= 0) return ret + i->ctn_increment; if (ctf_errno (fp) != ECTF_NEXT_END) { ctf_next_destroy (i); *it = NULL; i->ctn_type = 0; ctf_set_errno (ofp, ctf_errno (fp)); return ret; } if (!ctf_assert (fp, (i->ctn_next == NULL))) return (ctf_set_errno (ofp, ctf_errno (fp))); i->ctn_type = 0; /* This sub-struct has ended: on to the next real member. */ goto retry; } return offset; end_iter: ctf_next_destroy (i); *it = NULL; return ctf_set_errno (ofp, ECTF_NEXT_END);} /* Iterate over the members of an ENUM. We pass the string name and associated integer value of each enum element to the specified callback function. */ intctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg){ ctf_next_t *i = NULL; const char *name; int val; while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL) { int rc; if ((rc = func (name, val, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0;} /* Iterate over the members of an enum TYPE, returning each enumerand's NAME or NULL at end of iteration or error, and optionally passing back the enumerand's integer VALue. */ const char *ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, int *val){ ctf_dict_t *ofp = fp; uint32_t kind; const char *name; ctf_next_t *i = *it; if (!i) { const ctf_type_t *tp; ctf_dtdef_t *dtd; if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR) return NULL; /* errno is set for us. */ if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) return NULL; /* errno is set for us. */ if ((i = ctf_next_create ()) == NULL) { ctf_set_errno (ofp, ENOMEM); return NULL; } i->cu.ctn_fp = ofp; (void) ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment); kind = LCTF_INFO_KIND (fp, tp->ctt_info); if (kind != CTF_K_ENUM) { ctf_next_destroy (i); ctf_set_errno (ofp, ECTF_NOTENUM); return NULL; } dtd = ctf_dynamic_type (fp, type); i->ctn_iter_fun = (void (*) (void)) ctf_enum_next; i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); if (dtd == NULL) i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp + i->ctn_increment); else i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen; *it = i; } if ((void (*) (void)) ctf_enum_next != i->ctn_iter_fun) { ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN); return NULL; } if (ofp != i->cu.ctn_fp) { ctf_set_errno (ofp, ECTF_NEXT_WRONGFP); return NULL; } /* Resolve to the native dict of this type. */ if ((fp = ctf_get_dict (ofp, type)) == NULL) { ctf_set_errno (ofp, ECTF_NOPARENT); return NULL; } if (i->ctn_n == 0) goto end_iter; name = ctf_strptr (fp, i->u.ctn_en->cte_name); if (val) *val = i->u.ctn_en->cte_value; i->u.ctn_en++; i->ctn_n--; return name; end_iter: ctf_next_destroy (i); *it = NULL; ctf_set_errno (ofp, ECTF_NEXT_END); return NULL;} /* Iterate over every root (user-visible) type in the given CTF dict. We pass the type ID of each type to the specified callback function. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children of a single parent. */ intctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg){ ctf_next_t *i = NULL; ctf_id_t type; while ((type = ctf_type_next (fp, &i, NULL, 0)) != CTF_ERR) { int rc; if ((rc = func (type, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0;} /* Iterate over every type in the given CTF dict, user-visible or not. We pass the type ID of each type to the specified callback function. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children of a single parent. */ intctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg){ ctf_next_t *i = NULL; ctf_id_t type; int flag; while ((type = ctf_type_next (fp, &i, &flag, 1)) != CTF_ERR) { int rc; if ((rc = func (type, flag, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0;} /* Iterate over every type in the given CTF dict, optionally including non-user-visible types, returning each type ID and hidden flag in turn. Returns CTF_ERR on end of iteration or error. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children of a single parent. */ ctf_id_tctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden){ ctf_next_t *i = *it; if (!i) { if ((i = ctf_next_create ()) == NULL) return ctf_set_typed_errno (fp, ENOMEM); i->cu.ctn_fp = fp; i->ctn_type = 1; i->ctn_iter_fun = (void (*) (void)) ctf_type_next; *it = i; } if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun) return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); if (fp != i->cu.ctn_fp) return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); while (i->ctn_type <= fp->ctf_typemax) { const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, i->ctn_type); if ((!want_hidden) && (!LCTF_INFO_ISROOT (fp, tp->ctt_info))) { i->ctn_type++; continue; } if (flag) *flag = LCTF_INFO_ISROOT (fp, tp->ctt_info); return LCTF_INDEX_TO_TYPE (fp, i->ctn_type++, fp->ctf_flags & LCTF_CHILD); } ctf_next_destroy (i); *it = NULL; return ctf_set_typed_errno (fp, ECTF_NEXT_END);} /* Iterate over every variable in the given CTF dict, in arbitrary order. We pass the name of each variable to the specified callback function. */ intctf_variable_iter (ctf_dict_t *fp, ctf_variable_f *func, void *arg){ ctf_next_t *i = NULL; ctf_id_t type; const char *name; while ((type = ctf_variable_next (fp, &i, &name)) != CTF_ERR) { int rc; if ((rc = func (name, type, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0;} /* Iterate over every variable in the given CTF dict, in arbitrary order, returning the name and type of each variable in turn. The name argument is not optional. Returns CTF_ERR on end of iteration or error. */Lines 1–500 of 1723. Load more
/* Type handling functions. Copyright (C) 2019-2026 Free Software Foundation, Inc. This file is part of libctf. libctf is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not see <http://www.gnu.org/licenses/>. */ #include <ctf-impl.h> #include <assert.h> #include <string.h> /* Determine whether a type is a parent or a child. */ int ctf_type_isparent (ctf_dict_t *fp, ctf_id_t id) { return (LCTF_TYPE_ISPARENT (fp, id)); } int ctf_type_ischild (ctf_dict_t * fp, ctf_id_t id) { return (LCTF_TYPE_ISCHILD (fp, id)); } /* Expand a structure element into the passed-in ctf_lmember_t. */ static int ctf_struct_member (ctf_dict_t *fp, ctf_lmember_t *dst, const ctf_type_t *tp, unsigned char *vlen, size_t vbytes, size_t n) { if (!ctf_assert (fp, n < LCTF_INFO_VLEN (fp, tp->ctt_info))) return -1; /* errno is set for us. */ /* Already large. */ if (tp->ctt_size >= CTF_LSTRUCT_THRESH) { ctf_lmember_t *lmp = (ctf_lmember_t *) vlen; if (!ctf_assert (fp, (n + 1) * sizeof (ctf_lmember_t) <= vbytes)) return -1; /* errno is set for us. */ memcpy (dst, &lmp[n], sizeof (ctf_lmember_t)); } else { ctf_member_t *mp = (ctf_member_t *) vlen; dst->ctlm_name = mp[n].ctm_name; dst->ctlm_type = mp[n].ctm_type; dst->ctlm_offsetlo = mp[n].ctm_offset; dst->ctlm_offsethi = 0; } return 0; } /* Iterate over the members of a STRUCT or UNION. We pass the name, member type, and offset of each member to the specified callback function. */ int ctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) { ctf_next_t *i = NULL; ssize_t offset; const char *name; ctf_id_t membtype; while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0) { int rc; if ((rc = func (name, membtype, offset, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0; } /* Iterate over the members of a STRUCT or UNION, returning each member's offset and optionally name and member type in turn. On end-of-iteration, returns -1. If FLAGS is CTF_MN_RECURSE, recurse into unnamed members. */ ssize_t ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, const char **name, ctf_id_t *membtype, int flags) { ctf_dict_t *ofp = fp; uint32_t kind; ssize_t offset; uint32_t max_vlen; ctf_next_t *i = *it; if (!i) { const ctf_type_t *tp; ctf_dtdef_t *dtd; ssize_t size; ssize_t increment; if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) return -1; /* errno is set for us. */ if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) return -1; /* errno is set for us. */ if ((i = ctf_next_create ()) == NULL) return ctf_set_errno (ofp, ENOMEM); i->cu.ctn_fp = ofp; i->ctn_tp = tp; ctf_get_ctt_size (fp, tp, &size, &increment); kind = LCTF_INFO_KIND (fp, tp->ctt_info); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) { ctf_next_destroy (i); return (ctf_set_errno (ofp, ECTF_NOTSOU)); } if ((dtd = ctf_dynamic_type (fp, type)) != NULL) { i->u.ctn_vlen = dtd->dtd_vlen; i->ctn_size = dtd->dtd_vlen_alloc; } else { unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); i->u.ctn_vlen = (unsigned char *) tp + increment; i->ctn_size = LCTF_VBYTES (fp, kind, size, vlen);; } i->ctn_iter_fun = (void (*) (void)) ctf_member_next; i->ctn_n = 0; *it = i; } if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun) return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN)); if (ofp != i->cu.ctn_fp) return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP)); /* Resolve to the native dict of this type. */ if ((fp = ctf_get_dict (ofp, type)) == NULL) return (ctf_set_errno (ofp, ECTF_NOPARENT)); max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info); /* When we hit an unnamed struct/union member, we set ctn_type to indicate that we are inside one, then return the unnamed member: on the next call, we must skip over top-level member iteration in favour of iteration within the sub-struct until it later turns out that that iteration has ended. */ retry: if (!i->ctn_type) { ctf_lmember_t memb; const char *membname; if (i->ctn_n == max_vlen) goto end_iter; if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size, i->ctn_n) < 0) return (ctf_set_errno (ofp, ctf_errno (fp))); membname = ctf_strptr (fp, memb.ctlm_name); if (name) *name = membname; if (membtype) *membtype = memb.ctlm_type; offset = (unsigned long) CTF_LMEM_OFFSET (&memb); if (membname[0] == 0) { ctf_id_t resolved; if ((resolved = ctf_type_resolve (fp, memb.ctlm_type)) == CTF_ERR) { if (ctf_errno (fp) != ECTF_NONREPRESENTABLE) return -1; /* errno is set for us. */ resolved = memb.ctlm_type; } if (ctf_type_kind (fp, resolved) == CTF_K_STRUCT || ctf_type_kind (fp, resolved) == CTF_K_UNION) i->ctn_type = resolved; } i->ctn_n++; /* The callers might want automatic recursive sub-struct traversal. */ if (!(flags & CTF_MN_RECURSE)) i->ctn_type = 0; /* Sub-struct traversal starting? Take note of the offset of this member, for later boosting of sub-struct members' offsets. */ if (i->ctn_type) i->ctn_increment = offset; } /* Traversing a sub-struct? Just return it, with the offset adjusted. */ else { ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name, membtype, flags); if (ret >= 0) return ret + i->ctn_increment; if (ctf_errno (fp) != ECTF_NEXT_END) { ctf_next_destroy (i); *it = NULL; i->ctn_type = 0; ctf_set_errno (ofp, ctf_errno (fp)); return ret; } if (!ctf_assert (fp, (i->ctn_next == NULL))) return (ctf_set_errno (ofp, ctf_errno (fp))); i->ctn_type = 0; /* This sub-struct has ended: on to the next real member. */ goto retry; } return offset; end_iter: ctf_next_destroy (i); *it = NULL; return ctf_set_errno (ofp, ECTF_NEXT_END); } /* Iterate over the members of an ENUM. We pass the string name and associated integer value of each enum element to the specified callback function. */ int ctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg) { ctf_next_t *i = NULL; const char *name; int val; while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL) { int rc; if ((rc = func (name, val, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0; } /* Iterate over the members of an enum TYPE, returning each enumerand's NAME or NULL at end of iteration or error, and optionally passing back the enumerand's integer VALue. */ const char * ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, int *val) { ctf_dict_t *ofp = fp; uint32_t kind; const char *name; ctf_next_t *i = *it; if (!i) { const ctf_type_t *tp; ctf_dtdef_t *dtd; if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR) return NULL; /* errno is set for us. */ if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) return NULL; /* errno is set for us. */ if ((i = ctf_next_create ()) == NULL) { ctf_set_errno (ofp, ENOMEM); return NULL; } i->cu.ctn_fp = ofp; (void) ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment); kind = LCTF_INFO_KIND (fp, tp->ctt_info); if (kind != CTF_K_ENUM) { ctf_next_destroy (i); ctf_set_errno (ofp, ECTF_NOTENUM); return NULL; } dtd = ctf_dynamic_type (fp, type); i->ctn_iter_fun = (void (*) (void)) ctf_enum_next; i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); if (dtd == NULL) i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp + i->ctn_increment); else i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen; *it = i; } if ((void (*) (void)) ctf_enum_next != i->ctn_iter_fun) { ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN); return NULL; } if (ofp != i->cu.ctn_fp) { ctf_set_errno (ofp, ECTF_NEXT_WRONGFP); return NULL; } /* Resolve to the native dict of this type. */ if ((fp = ctf_get_dict (ofp, type)) == NULL) { ctf_set_errno (ofp, ECTF_NOPARENT); return NULL; } if (i->ctn_n == 0) goto end_iter; name = ctf_strptr (fp, i->u.ctn_en->cte_name); if (val) *val = i->u.ctn_en->cte_value; i->u.ctn_en++; i->ctn_n--; return name; end_iter: ctf_next_destroy (i); *it = NULL; ctf_set_errno (ofp, ECTF_NEXT_END); return NULL; } /* Iterate over every root (user-visible) type in the given CTF dict. We pass the type ID of each type to the specified callback function. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children of a single parent. */ int ctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg) { ctf_next_t *i = NULL; ctf_id_t type; while ((type = ctf_type_next (fp, &i, NULL, 0)) != CTF_ERR) { int rc; if ((rc = func (type, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0; } /* Iterate over every type in the given CTF dict, user-visible or not. We pass the type ID of each type to the specified callback function. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children of a single parent. */ int ctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg) { ctf_next_t *i = NULL; ctf_id_t type; int flag; while ((type = ctf_type_next (fp, &i, &flag, 1)) != CTF_ERR) { int rc; if ((rc = func (type, flag, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0; } /* Iterate over every type in the given CTF dict, optionally including non-user-visible types, returning each type ID and hidden flag in turn. Returns CTF_ERR on end of iteration or error. Does not traverse parent types: you have to do that explicitly. This is by design, to avoid traversing them more than once if traversing many children of a single parent. */ ctf_id_t ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden) { ctf_next_t *i = *it; if (!i) { if ((i = ctf_next_create ()) == NULL) return ctf_set_typed_errno (fp, ENOMEM); i->cu.ctn_fp = fp; i->ctn_type = 1; i->ctn_iter_fun = (void (*) (void)) ctf_type_next; *it = i; } if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun) return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN)); if (fp != i->cu.ctn_fp) return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP)); while (i->ctn_type <= fp->ctf_typemax) { const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, i->ctn_type); if ((!want_hidden) && (!LCTF_INFO_ISROOT (fp, tp->ctt_info))) { i->ctn_type++; continue; } if (flag) *flag = LCTF_INFO_ISROOT (fp, tp->ctt_info); return LCTF_INDEX_TO_TYPE (fp, i->ctn_type++, fp->ctf_flags & LCTF_CHILD); } ctf_next_destroy (i); *it = NULL; return ctf_set_typed_errno (fp, ECTF_NEXT_END); } /* Iterate over every variable in the given CTF dict, in arbitrary order. We pass the name of each variable to the specified callback function. */ int ctf_variable_iter (ctf_dict_t *fp, ctf_variable_f *func, void *arg) { ctf_next_t *i = NULL; ctf_id_t type; const char *name; while ((type = ctf_variable_next (fp, &i, &name)) != CTF_ERR) { int rc; if ((rc = func (name, type, arg)) != 0) { ctf_next_destroy (i); return rc; } } if (ctf_errno (fp) != ECTF_NEXT_END) return -1; /* errno is set for us. */ return 0; } /* Iterate over every variable in the given CTF dict, in arbitrary order, returning the name and type of each variable in turn. The name argument is not optional. Returns CTF_ERR on end of iteration or error. */