176082Sbmah/* Type handling functions. 276082Sbmah Copyright (C) 2019-2022 Free Software Foundation, Inc. 376082Sbmah 476082Sbmah This file is part of libctf. 576082Sbmah 676082Sbmah libctf is free software; you can redistribute it and/or modify it under 776082Sbmah the terms of the GNU General Public License as published by the Free 876082Sbmah Software Foundation; either version 3, or (at your option) any later 976082Sbmah version. 1076082Sbmah 1176082Sbmah This program is distributed in the hope that it will be useful, but 1276082Sbmah WITHOUT ANY WARRANTY; without even the implied warranty of 1386157Solgeni MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 1476082Sbmah See the GNU General Public License for more details. 1576082Sbmah 1676082Sbmah You should have received a copy of the GNU General Public License 1776082Sbmah along with this program; see the file COPYING. If not see 1876082Sbmah <http://www.gnu.org/licenses/>. */ 1976082Sbmah 2086157Solgeni#include <ctf-impl.h> 2176082Sbmah#include <assert.h> 2276082Sbmah#include <string.h> 2376560Sbmah 2476560Sbmah/* Determine whether a type is a parent or a child. */ 2576560Sbmah 2676560Sbmahint 2776560Sbmahctf_type_isparent (ctf_dict_t *fp, ctf_id_t id) 2876560Sbmah{ 2976560Sbmah return (LCTF_TYPE_ISPARENT (fp, id)); 3076082Sbmah} 3176082Sbmah 3276082Sbmahint 3376598Sbmahctf_type_ischild (ctf_dict_t * fp, ctf_id_t id) 3476598Sbmah{ 3576598Sbmah return (LCTF_TYPE_ISCHILD (fp, id)); 3676598Sbmah} 3776082Sbmah 3876082Sbmah/* Expand a structure element into the passed-in ctf_lmember_t. */ 3976082Sbmah 4085416Sbmahstatic int 4176082Sbmahctf_struct_member (ctf_dict_t *fp, ctf_lmember_t *dst, const ctf_type_t *tp, 4276082Sbmah unsigned char *vlen, size_t vbytes, size_t n) 4376082Sbmah{ 4476560Sbmah if (!ctf_assert (fp, n < LCTF_INFO_VLEN (fp, tp->ctt_info))) 4576560Sbmah return -1; /* errno is set for us. */ 4676560Sbmah 4776560Sbmah /* Already large. */ 4876082Sbmah if (tp->ctt_size == CTF_LSIZE_SENT) 4976082Sbmah { 5087808Sbmah ctf_lmember_t *lmp = (ctf_lmember_t *) vlen; 5176082Sbmah 5276082Sbmah if (!ctf_assert (fp, (n + 1) * sizeof (ctf_lmember_t) <= vbytes)) 5376082Sbmah return -1; /* errno is set for us. */ 5476082Sbmah 5576082Sbmah memcpy (dst, &lmp[n], sizeof (ctf_lmember_t)); 5684568Sbmah } 5776082Sbmah else 5876082Sbmah { 5976082Sbmah ctf_member_t *mp = (ctf_member_t *) vlen; 6076082Sbmah dst->ctlm_name = mp[n].ctm_name; 6176082Sbmah dst->ctlm_type = mp[n].ctm_type; 6276082Sbmah dst->ctlm_offsetlo = mp[n].ctm_offset; 6376082Sbmah dst->ctlm_offsethi = 0; 6476082Sbmah } 6576082Sbmah return 0; 6676082Sbmah} 6776082Sbmah 6888889Sbmah/* Iterate over the members of a STRUCT or UNION. We pass the name, member 6976082Sbmah type, and offset of each member to the specified callback function. */ 7076082Sbmah 7176082Sbmahint 7276082Sbmahctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) 7376082Sbmah{ 7486055Sbmah ctf_next_t *i = NULL; 7576082Sbmah ssize_t offset; 7676082Sbmah const char *name; 7776082Sbmah ctf_id_t membtype; 7876082Sbmah 7976082Sbmah while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0) 8084568Sbmah { 8176082Sbmah int rc; 8276082Sbmah if ((rc = func (name, membtype, offset, arg)) != 0) 8376082Sbmah { 8476082Sbmah ctf_next_destroy (i); 8576082Sbmah return rc; 8676082Sbmah } 8776082Sbmah } 8876082Sbmah if (ctf_errno (fp) != ECTF_NEXT_END) 8987357Sbmah return -1; /* errno is set for us. */ 9087357Sbmah 9187357Sbmah return 0; 9287357Sbmah} 9387357Sbmah 9487357Sbmah/* Iterate over the members of a STRUCT or UNION, returning each member's 9576082Sbmah offset and optionally name and member type in turn. On end-of-iteration, 9676082Sbmah returns -1. If FLAGS is CTF_MN_RECURSE, recurse into unnamed members. */ 9776082Sbmah 9886055Sbmahssize_t 9976082Sbmahctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, 10076082Sbmah const char **name, ctf_id_t *membtype, int flags) 10176082Sbmah{ 10287993Sbmah ctf_dict_t *ofp = fp; 10376082Sbmah uint32_t kind; 10487993Sbmah ssize_t offset; 10576082Sbmah uint32_t max_vlen; 10676082Sbmah ctf_next_t *i = *it; 10787993Sbmah 10876560Sbmah if (!i) 10976560Sbmah { 11076082Sbmah const ctf_type_t *tp; 11176082Sbmah ctf_dtdef_t *dtd; 11276560Sbmah ssize_t size; 11376560Sbmah ssize_t increment; 11476082Sbmah 11576082Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 11676082Sbmah return -1; /* errno is set for us. */ 11786139Sbmah 11876082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 11986896Sbmah return -1; /* errno is set for us. */ 12086896Sbmah 12186896Sbmah if ((i = ctf_next_create ()) == NULL) 12286896Sbmah return ctf_set_errno (ofp, ENOMEM); 12386896Sbmah i->cu.ctn_fp = ofp; 12486896Sbmah i->ctn_tp = tp; 12586896Sbmah 12686896Sbmah ctf_get_ctt_size (fp, tp, &size, &increment); 12786896Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 12886896Sbmah 12986896Sbmah if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 13086896Sbmah { 13186896Sbmah ctf_next_destroy (i); 13276560Sbmah return (ctf_set_errno (ofp, ECTF_NOTSOU)); 13376560Sbmah } 13476082Sbmah 13586896Sbmah if ((dtd = ctf_dynamic_type (fp, type)) != NULL) 13676560Sbmah { 13776560Sbmah i->u.ctn_vlen = dtd->dtd_vlen; 13876560Sbmah i->ctn_size = dtd->dtd_vlen_alloc; 13976082Sbmah } 14076082Sbmah else 14176082Sbmah { 14276082Sbmah unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); 14376082Sbmah 14476082Sbmah i->u.ctn_vlen = (unsigned char *) tp + increment; 14576560Sbmah i->ctn_size = LCTF_VBYTES (fp, kind, size, vlen);; 14676560Sbmah } 14776082Sbmah i->ctn_iter_fun = (void (*) (void)) ctf_member_next; 14876082Sbmah i->ctn_n = 0; 14976082Sbmah *it = i; 15076560Sbmah } 15176560Sbmah 15276082Sbmah if ((void (*) (void)) ctf_member_next != i->ctn_iter_fun) 15376082Sbmah return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN)); 15476082Sbmah 15576082Sbmah if (ofp != i->cu.ctn_fp) 15682597Sscottl return (ctf_set_errno (ofp, ECTF_NEXT_WRONGFP)); 15776082Sbmah 15876082Sbmah /* Resolve to the native dict of this type. */ 15982597Sscottl if ((fp = ctf_get_dict (ofp, type)) == NULL) 16082597Sscottl return (ctf_set_errno (ofp, ECTF_NOPARENT)); 16182597Sscottl 16276396Sscottl max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info); 16376396Sscottl 16476396Sscottl /* When we hit an unnamed struct/union member, we set ctn_type to indicate 16576082Sbmah that we are inside one, then return the unnamed member: on the next call, 16676082Sbmah we must skip over top-level member iteration in favour of iteration within 16776082Sbmah the sub-struct until it later turns out that that iteration has ended. */ 16876082Sbmah 16976082Sbmah retry: 17076082Sbmah if (!i->ctn_type) 17176082Sbmah { 17276082Sbmah ctf_lmember_t memb; 17376082Sbmah const char *membname; 17482597Sscottl 17576082Sbmah if (i->ctn_n == max_vlen) 17676082Sbmah goto end_iter; 17776082Sbmah 17876082Sbmah if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size, 17976082Sbmah i->ctn_n) < 0) 18076082Sbmah return -1; /* errno is set for us. */ 18176082Sbmah 18276082Sbmah membname = ctf_strptr (fp, memb.ctlm_name); 18376082Sbmah 18476082Sbmah if (name) 18576082Sbmah *name = membname; 18676082Sbmah if (membtype) 18776082Sbmah *membtype = memb.ctlm_type; 18876082Sbmah offset = (unsigned long) CTF_LMEM_OFFSET (&memb); 18976082Sbmah 19076082Sbmah if (membname[0] == 0 19176082Sbmah && (ctf_type_kind (fp, memb.ctlm_type) == CTF_K_STRUCT 19276082Sbmah || ctf_type_kind (fp, memb.ctlm_type) == CTF_K_UNION)) 19376082Sbmah i->ctn_type = memb.ctlm_type; 19476082Sbmah i->ctn_n++; 19576082Sbmah 19676082Sbmah /* The callers might want automatic recursive sub-struct traversal. */ 19787993Sbmah if (!(flags & CTF_MN_RECURSE)) 19876082Sbmah i->ctn_type = 0; 19976082Sbmah 20087993Sbmah /* Sub-struct traversal starting? Take note of the offset of this member, 20176082Sbmah for later boosting of sub-struct members' offsets. */ 20276082Sbmah if (i->ctn_type) 20376082Sbmah i->ctn_increment = offset; 20476082Sbmah } 20576082Sbmah /* Traversing a sub-struct? Just return it, with the offset adjusted. */ 20676082Sbmah else 20776082Sbmah { 20876082Sbmah ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name, 20976082Sbmah membtype, flags); 21076082Sbmah 21176082Sbmah if (ret >= 0) 21276082Sbmah return ret + i->ctn_increment; 21376082Sbmah 21476082Sbmah if (ctf_errno (fp) != ECTF_NEXT_END) 21587993Sbmah { 21676082Sbmah ctf_next_destroy (i); 21776082Sbmah *it = NULL; 21876082Sbmah i->ctn_type = 0; 21976082Sbmah return ret; /* errno is set for us. */ 22076082Sbmah } 22176082Sbmah 22276082Sbmah if (!ctf_assert (fp, (i->ctn_next == NULL))) 22376082Sbmah return -1; /* errno is set for us. */ 22476082Sbmah 22576082Sbmah i->ctn_type = 0; 22676082Sbmah /* This sub-struct has ended: on to the next real member. */ 22776082Sbmah goto retry; 22876082Sbmah } 22976082Sbmah 23076082Sbmah return offset; 23176082Sbmah 23276082Sbmah end_iter: 23376082Sbmah ctf_next_destroy (i); 23476082Sbmah *it = NULL; 23576082Sbmah return ctf_set_errno (ofp, ECTF_NEXT_END); 23676082Sbmah} 23776082Sbmah 23876082Sbmah/* Iterate over the members of an ENUM. We pass the string name and associated 23976082Sbmah integer value of each enum element to the specified callback function. */ 24076082Sbmah 24176082Sbmahint 24276082Sbmahctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg) 24376082Sbmah{ 24476082Sbmah ctf_next_t *i = NULL; 24576082Sbmah const char *name; 24676082Sbmah int val; 24776082Sbmah 24887993Sbmah while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL) 24976082Sbmah { 25076082Sbmah int rc; 25176082Sbmah if ((rc = func (name, val, arg)) != 0) 25276082Sbmah { 25376082Sbmah ctf_next_destroy (i); 25476082Sbmah return rc; 25576082Sbmah } 25676082Sbmah } 25776082Sbmah if (ctf_errno (fp) != ECTF_NEXT_END) 25876082Sbmah return -1; /* errno is set for us. */ 25976082Sbmah 26076082Sbmah return 0; 26176082Sbmah} 26276082Sbmah 26376082Sbmah/* Iterate over the members of an enum TYPE, returning each enumerand's NAME or 26476082Sbmah NULL at end of iteration or error, and optionally passing back the 26576082Sbmah enumerand's integer VALue. */ 26676082Sbmah 26776082Sbmahconst char * 26876082Sbmahctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, 26976082Sbmah int *val) 27076082Sbmah{ 27176082Sbmah ctf_dict_t *ofp = fp; 27276082Sbmah uint32_t kind; 27376082Sbmah const char *name; 27476082Sbmah ctf_next_t *i = *it; 27576082Sbmah 27676082Sbmah if (!i) 27776082Sbmah { 27876082Sbmah const ctf_type_t *tp; 27976082Sbmah ctf_dtdef_t *dtd; 28076082Sbmah 28187993Sbmah if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR) 28276082Sbmah return NULL; /* errno is set for us. */ 28376082Sbmah 28476082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 28576082Sbmah return NULL; /* errno is set for us. */ 28676082Sbmah 28776082Sbmah if ((i = ctf_next_create ()) == NULL) 28876082Sbmah { 28976082Sbmah ctf_set_errno (ofp, ENOMEM); 29076082Sbmah return NULL; 29176082Sbmah } 29276082Sbmah i->cu.ctn_fp = ofp; 29387993Sbmah 29476082Sbmah (void) ctf_get_ctt_size (fp, tp, NULL, 29576082Sbmah &i->ctn_increment); 29676082Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 29787993Sbmah 29876082Sbmah if (kind != CTF_K_ENUM) 29976082Sbmah { 30076082Sbmah ctf_next_destroy (i); 30176082Sbmah ctf_set_errno (ofp, ECTF_NOTENUM); 30276082Sbmah return NULL; 30376082Sbmah } 30476082Sbmah 30576082Sbmah dtd = ctf_dynamic_type (fp, type); 30676082Sbmah i->ctn_iter_fun = (void (*) (void)) ctf_enum_next; 30776082Sbmah i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); 30887993Sbmah 30976082Sbmah if (dtd == NULL) 31076082Sbmah i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp + 31176082Sbmah i->ctn_increment); 31276560Sbmah else 31376082Sbmah i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen; 31476082Sbmah 31576082Sbmah *it = i; 31676082Sbmah } 31776082Sbmah 31876082Sbmah if ((void (*) (void)) ctf_enum_next != i->ctn_iter_fun) 31976082Sbmah { 32076082Sbmah ctf_set_errno (ofp, ECTF_NEXT_WRONGFUN); 32176082Sbmah return NULL; 32276082Sbmah } 32376082Sbmah 32476082Sbmah if (ofp != i->cu.ctn_fp) 32576082Sbmah { 32676082Sbmah ctf_set_errno (ofp, ECTF_NEXT_WRONGFP); 32776082Sbmah return NULL; 32876082Sbmah } 32976082Sbmah 33076082Sbmah /* Resolve to the native dict of this type. */ 33176082Sbmah if ((fp = ctf_get_dict (ofp, type)) == NULL) 33276082Sbmah { 33376082Sbmah ctf_set_errno (ofp, ECTF_NOPARENT); 33476082Sbmah return NULL; 33576082Sbmah } 33676082Sbmah 33776082Sbmah if (i->ctn_n == 0) 33886896Sbmah goto end_iter; 33976082Sbmah 34076082Sbmah name = ctf_strptr (fp, i->u.ctn_en->cte_name); 34176082Sbmah if (val) 34276082Sbmah *val = i->u.ctn_en->cte_value; 34376082Sbmah i->u.ctn_en++; 34476082Sbmah i->ctn_n--; 34576082Sbmah 34676082Sbmah return name; 34776082Sbmah 34876082Sbmah end_iter: 34976082Sbmah ctf_next_destroy (i); 35076082Sbmah *it = NULL; 35176082Sbmah ctf_set_errno (ofp, ECTF_NEXT_END); 35276082Sbmah return NULL; 35376082Sbmah} 35476082Sbmah 35576082Sbmah/* Iterate over every root (user-visible) type in the given CTF dict. 35676082Sbmah We pass the type ID of each type to the specified callback function. 35776082Sbmah 35876082Sbmah Does not traverse parent types: you have to do that explicitly. This is by 35976082Sbmah design, to avoid traversing them more than once if traversing many children 36076082Sbmah of a single parent. */ 36176082Sbmah 36276082Sbmahint 36376082Sbmahctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg) 36476082Sbmah{ 36576082Sbmah ctf_next_t *i = NULL; 36676082Sbmah ctf_id_t type; 36776082Sbmah 36876082Sbmah while ((type = ctf_type_next (fp, &i, NULL, 0)) != CTF_ERR) 36976082Sbmah { 37076082Sbmah int rc; 37176082Sbmah if ((rc = func (type, arg)) != 0) 37276082Sbmah { 37376082Sbmah ctf_next_destroy (i); 37476082Sbmah return rc; 37576082Sbmah } 37676082Sbmah } 37776082Sbmah if (ctf_errno (fp) != ECTF_NEXT_END) 37876082Sbmah return -1; /* errno is set for us. */ 37976082Sbmah 38076082Sbmah return 0; 38176082Sbmah} 38276082Sbmah 38376082Sbmah/* Iterate over every type in the given CTF dict, user-visible or not. 38476082Sbmah We pass the type ID of each type to the specified callback function. 38576082Sbmah 38676082Sbmah Does not traverse parent types: you have to do that explicitly. This is by 38776082Sbmah design, to avoid traversing them more than once if traversing many children 38876082Sbmah of a single parent. */ 38976082Sbmah 39076082Sbmahint 39176082Sbmahctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg) 39276082Sbmah{ 39376082Sbmah ctf_next_t *i = NULL; 39476082Sbmah ctf_id_t type; 39576082Sbmah int flag; 39676082Sbmah 39776082Sbmah while ((type = ctf_type_next (fp, &i, &flag, 1)) != CTF_ERR) 39876082Sbmah { 39976082Sbmah int rc; 40087767Sbmah if ((rc = func (type, flag, arg)) != 0) 40187767Sbmah { 40287842Sbmah ctf_next_destroy (i); 40376082Sbmah return rc; 40487767Sbmah } 40587767Sbmah } 40687767Sbmah if (ctf_errno (fp) != ECTF_NEXT_END) 40787767Sbmah return -1; /* errno is set for us. */ 40876082Sbmah 40986896Sbmah return 0; 41076082Sbmah} 41176082Sbmah 41276082Sbmah/* Iterate over every type in the given CTF dict, optionally including 41376082Sbmah non-user-visible types, returning each type ID and hidden flag in turn. 41476082Sbmah Returns CTF_ERR on end of iteration or error. 41576082Sbmah 41676082Sbmah Does not traverse parent types: you have to do that explicitly. This is by 41776082Sbmah design, to avoid traversing them more than once if traversing many children 41876082Sbmah of a single parent. */ 41976082Sbmah 42076082Sbmahctf_id_t 42176082Sbmahctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden) 42276082Sbmah{ 42376082Sbmah ctf_next_t *i = *it; 42476082Sbmah 42576082Sbmah if (!i) 42676082Sbmah { 42776082Sbmah if ((i = ctf_next_create ()) == NULL) 42876082Sbmah return ctf_set_errno (fp, ENOMEM); 42976082Sbmah 43076082Sbmah i->cu.ctn_fp = fp; 43176082Sbmah i->ctn_type = 1; 43276082Sbmah i->ctn_iter_fun = (void (*) (void)) ctf_type_next; 43376082Sbmah *it = i; 43476082Sbmah } 43576082Sbmah 43676082Sbmah if ((void (*) (void)) ctf_type_next != i->ctn_iter_fun) 43776082Sbmah return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN)); 43876082Sbmah 43976082Sbmah if (fp != i->cu.ctn_fp) 44087767Sbmah return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP)); 44187767Sbmah 44287767Sbmah while (i->ctn_type <= fp->ctf_typemax) 44387767Sbmah { 44487767Sbmah const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, i->ctn_type); 44587767Sbmah 44687767Sbmah if ((!want_hidden) && (!LCTF_INFO_ISROOT (fp, tp->ctt_info))) 44787767Sbmah { 44887767Sbmah i->ctn_type++; 44987767Sbmah continue; 45076082Sbmah } 45176082Sbmah 45276082Sbmah if (flag) 45376082Sbmah *flag = LCTF_INFO_ISROOT (fp, tp->ctt_info); 45476082Sbmah return LCTF_INDEX_TO_TYPE (fp, i->ctn_type++, fp->ctf_flags & LCTF_CHILD); 45576082Sbmah } 45676082Sbmah ctf_next_destroy (i); 45776082Sbmah *it = NULL; 45876082Sbmah return ctf_set_errno (fp, ECTF_NEXT_END); 45976082Sbmah} 46076082Sbmah 46176082Sbmah/* Iterate over every variable in the given CTF dict, in arbitrary order. 46276082Sbmah We pass the name of each variable to the specified callback function. */ 46376082Sbmah 46476082Sbmahint 46576082Sbmahctf_variable_iter (ctf_dict_t *fp, ctf_variable_f *func, void *arg) 46676082Sbmah{ 46776082Sbmah ctf_next_t *i = NULL; 46876082Sbmah ctf_id_t type; 46976082Sbmah const char *name; 47076082Sbmah 47187767Sbmah while ((type = ctf_variable_next (fp, &i, &name)) != CTF_ERR) 47287767Sbmah { 47387767Sbmah int rc; 47487767Sbmah if ((rc = func (name, type, arg)) != 0) 47587767Sbmah { 47676082Sbmah ctf_next_destroy (i); 47776082Sbmah return rc; 47887993Sbmah } 47976082Sbmah } 48087993Sbmah if (ctf_errno (fp) != ECTF_NEXT_END) 48176082Sbmah return -1; /* errno is set for us. */ 48276082Sbmah 48376082Sbmah return 0; 48476082Sbmah} 48576082Sbmah 48676082Sbmah/* Iterate over every variable in the given CTF dict, in arbitrary order, 48776082Sbmah returning the name and type of each variable in turn. The name argument is 48876082Sbmah not optional. Returns CTF_ERR on end of iteration or error. */ 48976082Sbmah 49076082Sbmahctf_id_t 49176082Sbmahctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name) 49276082Sbmah{ 49376082Sbmah ctf_next_t *i = *it; 49491287Sbmah 49576082Sbmah if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL)) 49676082Sbmah return (ctf_set_errno (fp, ECTF_NOPARENT)); 49776082Sbmah 49876560Sbmah if (!i) 49976082Sbmah { 50076082Sbmah if ((i = ctf_next_create ()) == NULL) 50176082Sbmah return ctf_set_errno (fp, ENOMEM); 50276082Sbmah 50376082Sbmah i->cu.ctn_fp = fp; 50476082Sbmah i->ctn_iter_fun = (void (*) (void)) ctf_variable_next; 50576082Sbmah if (fp->ctf_flags & LCTF_RDWR) 50676082Sbmah i->u.ctn_dvd = ctf_list_next (&fp->ctf_dvdefs); 50776082Sbmah *it = i; 50876082Sbmah } 50976082Sbmah 51076082Sbmah if ((void (*) (void)) ctf_variable_next != i->ctn_iter_fun) 51176082Sbmah return (ctf_set_errno (fp, ECTF_NEXT_WRONGFUN)); 51276082Sbmah 51376082Sbmah if (fp != i->cu.ctn_fp) 51476082Sbmah return (ctf_set_errno (fp, ECTF_NEXT_WRONGFP)); 51576082Sbmah 51676082Sbmah if (!(fp->ctf_flags & LCTF_RDWR)) 51776082Sbmah { 51876082Sbmah if (i->ctn_n >= fp->ctf_nvars) 51976082Sbmah goto end_iter; 52076082Sbmah 52176082Sbmah *name = ctf_strptr (fp, fp->ctf_vars[i->ctn_n].ctv_name); 52276082Sbmah return fp->ctf_vars[i->ctn_n++].ctv_type; 52376082Sbmah } 52476082Sbmah else 52576082Sbmah { 52676082Sbmah ctf_id_t id; 52776082Sbmah 52876560Sbmah if (i->u.ctn_dvd == NULL) 52976560Sbmah goto end_iter; 53076082Sbmah 53176082Sbmah *name = i->u.ctn_dvd->dvd_name; 53276082Sbmah id = i->u.ctn_dvd->dvd_type; 53376082Sbmah i->u.ctn_dvd = ctf_list_next (i->u.ctn_dvd); 53476082Sbmah return id; 53576560Sbmah } 53676082Sbmah 53776082Sbmah end_iter: 53876082Sbmah ctf_next_destroy (i); 53976082Sbmah *it = NULL; 54076082Sbmah return ctf_set_errno (fp, ECTF_NEXT_END); 54176082Sbmah} 54276082Sbmah 54376082Sbmah/* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and 54476082Sbmah RESTRICT nodes until we reach a "base" type node. This is useful when 54576082Sbmah we want to follow a type ID to a node that has members or a size. To guard 54676082Sbmah against infinite loops, we implement simplified cycle detection and check 54776082Sbmah each link against itself, the previous node, and the topmost node. 54876082Sbmah 54976082Sbmah Does not drill down through slices to their contained type. 55087842Sbmah 55176082Sbmah Callers of this function must not presume that a type it returns must have a 55276082Sbmah valid ctt_size: forwards do not, and must be separately handled. */ 55376082Sbmah 55476082Sbmahctf_id_t 55576082Sbmahctf_type_resolve (ctf_dict_t *fp, ctf_id_t type) 55676082Sbmah{ 55776082Sbmah ctf_id_t prev = type, otype = type; 55876560Sbmah ctf_dict_t *ofp = fp; 55976560Sbmah const ctf_type_t *tp; 56076082Sbmah 56176082Sbmah if (type == 0) 56276082Sbmah return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE)); 56376082Sbmah 56476082Sbmah while ((tp = ctf_lookup_by_id (&fp, type)) != NULL) 56576082Sbmah { 56676082Sbmah switch (LCTF_INFO_KIND (fp, tp->ctt_info)) 56776082Sbmah { 56876082Sbmah case CTF_K_TYPEDEF: 56976082Sbmah case CTF_K_VOLATILE: 57076082Sbmah case CTF_K_CONST: 57176082Sbmah case CTF_K_RESTRICT: 57276082Sbmah if (tp->ctt_type == type || tp->ctt_type == otype 57376082Sbmah || tp->ctt_type == prev) 57476082Sbmah { 57576082Sbmah ctf_err_warn (ofp, 0, ECTF_CORRUPT, _("type %lx cycle detected"), 57676082Sbmah otype); 57776082Sbmah return (ctf_set_errno (ofp, ECTF_CORRUPT)); 57876082Sbmah } 57976082Sbmah prev = type; 58087842Sbmah type = tp->ctt_type; 58176082Sbmah break; 58276082Sbmah case CTF_K_UNKNOWN: 58387842Sbmah return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE)); 58476082Sbmah default: 58576082Sbmah return type; 58676082Sbmah } 58787842Sbmah if (type == 0) 58876082Sbmah return (ctf_set_errno (ofp, ECTF_NONREPRESENTABLE)); 58976082Sbmah } 59087842Sbmah 59176082Sbmah return CTF_ERR; /* errno is set for us. */ 59276082Sbmah} 59376082Sbmah 59487842Sbmah/* Like ctf_type_resolve(), but traverse down through slices to their contained 59576082Sbmah type. */ 59676082Sbmah 59787842Sbmahctf_id_t 59876082Sbmahctf_type_resolve_unsliced (ctf_dict_t *fp, ctf_id_t type) 59976082Sbmah{ 60076082Sbmah const ctf_type_t *tp; 60187842Sbmah 60282695Smjacob if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 60382695Smjacob return -1; 60482695Smjacob 60576082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 60676082Sbmah return CTF_ERR; /* errno is set for us. */ 60776082Sbmah 60876082Sbmah if ((LCTF_INFO_KIND (fp, tp->ctt_info)) == CTF_K_SLICE) 60976082Sbmah return ctf_type_reference (fp, type); 61076082Sbmah return type; 61176082Sbmah} 61276082Sbmah 61376082Sbmah/* Return the native dict of a given type: if called on a child and the 61476082Sbmah type is in the parent, return the parent. Needed if you plan to access 61576082Sbmah the type directly, without using the API. */ 61676082Sbmahctf_dict_t * 61776082Sbmahctf_get_dict (ctf_dict_t *fp, ctf_id_t type) 61876082Sbmah{ 61976082Sbmah if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type)) 62076082Sbmah return fp->ctf_parent; 62191515Sbmah 62276082Sbmah return fp; 62376082Sbmah} 62476560Sbmah 62576560Sbmah/* Look up a name in the given name table, in the appropriate hash given the 62676082Sbmah kind of the identifier. The name is a raw, undecorated identifier. */ 62776082Sbmah 62876082Sbmahctf_id_t ctf_lookup_by_rawname (ctf_dict_t *fp, int kind, const char *name) 62976082Sbmah{ 63076082Sbmah return ctf_lookup_by_rawhash (fp, ctf_name_table (fp, kind), name); 63176082Sbmah} 63276082Sbmah 63376082Sbmah/* Look up a name in the given name table, in the appropriate hash given the 63476082Sbmah readability state of the dictionary. The name is a raw, undecorated 63576082Sbmah identifier. */ 63676560Sbmah 63776560Sbmahctf_id_t ctf_lookup_by_rawhash (ctf_dict_t *fp, ctf_names_t *np, const char *name) 63876560Sbmah{ 63976560Sbmah ctf_id_t id; 64076560Sbmah 64176560Sbmah if (fp->ctf_flags & LCTF_RDWR) 64276560Sbmah id = (ctf_id_t) (uintptr_t) ctf_dynhash_lookup (np->ctn_writable, name); 64376560Sbmah else 64476560Sbmah id = ctf_hash_lookup_type (np->ctn_readonly, fp, name); 64576560Sbmah return id; 64676560Sbmah} 64776560Sbmah 64876560Sbmah/* Lookup the given type ID and return its name as a new dynamically-allocated 64976560Sbmah string. */ 65076560Sbmah 65187100Sbmahchar * 65287100Sbmahctf_type_aname (ctf_dict_t *fp, ctf_id_t type) 65387100Sbmah{ 65487100Sbmah ctf_decl_t cd; 65587100Sbmah ctf_decl_node_t *cdp; 65687100Sbmah ctf_decl_prec_t prec, lp, rp; 65787100Sbmah int ptr, arr; 65887100Sbmah uint32_t k; 65987100Sbmah char *buf; 66090031Sbmah 66190031Sbmah if (fp == NULL && type == CTF_ERR) 66290031Sbmah return NULL; /* Simplify caller code by permitting CTF_ERR. */ 66390031Sbmah 66490031Sbmah ctf_decl_init (&cd); 66590031Sbmah ctf_decl_push (&cd, fp, type); 66690031Sbmah 66790031Sbmah if (cd.cd_err != 0) 66890031Sbmah { 66990031Sbmah ctf_decl_fini (&cd); 67090031Sbmah ctf_set_errno (fp, cd.cd_err); 67190031Sbmah return NULL; 67276082Sbmah } 67376082Sbmah 67476082Sbmah /* If the type graph's order conflicts with lexical precedence order 67576082Sbmah for pointers or arrays, then we need to surround the declarations at 67676082Sbmah the corresponding lexical precedence with parentheses. This can 67776082Sbmah result in either a parenthesized pointer (*) as in int (*)() or 67876082Sbmah int (*)[], or in a parenthesized pointer and array as in int (*[])(). */ 67987842Sbmah 68091356Sdd ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; 68176082Sbmah arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; 68276082Sbmah 68376082Sbmah rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; 68476082Sbmah lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; 68576082Sbmah 68676082Sbmah k = CTF_K_POINTER; /* Avoid leading whitespace (see below). */ 68776082Sbmah 68876082Sbmah for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) 68976082Sbmah { 69076082Sbmah for (cdp = ctf_list_next (&cd.cd_nodes[prec]); 69176082Sbmah cdp != NULL; cdp = ctf_list_next (cdp)) 69276082Sbmah { 69376082Sbmah ctf_dict_t *rfp = fp; 69476082Sbmah const ctf_type_t *tp = ctf_lookup_by_id (&rfp, cdp->cd_type); 69576082Sbmah const char *name = ctf_strptr (rfp, tp->ctt_name); 69676082Sbmah 69776082Sbmah if (k != CTF_K_POINTER && k != CTF_K_ARRAY) 69876082Sbmah ctf_decl_sprintf (&cd, " "); 69976082Sbmah 70076082Sbmah if (lp == prec) 70176082Sbmah { 70276082Sbmah ctf_decl_sprintf (&cd, "("); 70376082Sbmah lp = -1; 70476082Sbmah } 70576082Sbmah 70676082Sbmah switch (cdp->cd_kind) 70776082Sbmah { 70876082Sbmah case CTF_K_INTEGER: 70976082Sbmah case CTF_K_FLOAT: 71076082Sbmah case CTF_K_TYPEDEF: 71176082Sbmah /* Integers, floats, and typedefs must always be named types. */ 71276082Sbmah 71376082Sbmah if (name[0] == '\0') 71476082Sbmah { 71576082Sbmah ctf_set_errno (fp, ECTF_CORRUPT); 71676082Sbmah ctf_decl_fini (&cd); 71776082Sbmah return NULL; 71876082Sbmah } 71976082Sbmah 72076082Sbmah ctf_decl_sprintf (&cd, "%s", name); 72176082Sbmah break; 72276082Sbmah case CTF_K_POINTER: 72376082Sbmah ctf_decl_sprintf (&cd, "*"); 72476082Sbmah break; 72576082Sbmah case CTF_K_ARRAY: 72676082Sbmah ctf_decl_sprintf (&cd, "[%u]", cdp->cd_n); 72776082Sbmah break; 72876082Sbmah case CTF_K_FUNCTION: 72976082Sbmah { 73076082Sbmah size_t i; 73176082Sbmah ctf_funcinfo_t fi; 73276082Sbmah ctf_id_t *argv = NULL; 73376082Sbmah 73476082Sbmah if (ctf_func_type_info (rfp, cdp->cd_type, &fi) < 0) 73576082Sbmah goto err; /* errno is set for us. */ 73676082Sbmah 73776082Sbmah if ((argv = calloc (fi.ctc_argc, sizeof (ctf_id_t *))) == NULL) 73876082Sbmah { 73976082Sbmah ctf_set_errno (rfp, errno); 74076082Sbmah goto err; 74176082Sbmah } 74276082Sbmah 74376082Sbmah if (ctf_func_type_args (rfp, cdp->cd_type, 74486896Sbmah fi.ctc_argc, argv) < 0) 74593404Skeramida goto err; /* errno is set for us. */ 74676082Sbmah 74776082Sbmah ctf_decl_sprintf (&cd, "(*) ("); 74876082Sbmah for (i = 0; i < fi.ctc_argc; i++) 74976082Sbmah { 75076082Sbmah char *arg = ctf_type_aname (rfp, argv[i]); 75176082Sbmah 75276082Sbmah if (arg == NULL) 75376082Sbmah goto err; /* errno is set for us. */ 75476082Sbmah ctf_decl_sprintf (&cd, "%s", arg); 75576082Sbmah free (arg); 75676082Sbmah 75776082Sbmah if ((i < fi.ctc_argc - 1) 75876082Sbmah || (fi.ctc_flags & CTF_FUNC_VARARG)) 75976082Sbmah ctf_decl_sprintf (&cd, ", "); 76076082Sbmah } 76176082Sbmah 76276082Sbmah if (fi.ctc_flags & CTF_FUNC_VARARG) 76376082Sbmah ctf_decl_sprintf (&cd, "..."); 76476082Sbmah ctf_decl_sprintf (&cd, ")"); 76576082Sbmah 76676560Sbmah free (argv); 76791515Sbmah break; 76889513Sbmah 76989513Sbmah err: 77089513Sbmah free (argv); 77189513Sbmah ctf_decl_fini (&cd); 77289513Sbmah return NULL; 77389513Sbmah } 77489513Sbmah break; 77589513Sbmah case CTF_K_STRUCT: 77689513Sbmah ctf_decl_sprintf (&cd, "struct %s", name); 77789513Sbmah break; 77889513Sbmah case CTF_K_UNION: 77989513Sbmah ctf_decl_sprintf (&cd, "union %s", name); 78089513Sbmah break; 78189513Sbmah case CTF_K_ENUM: 78289513Sbmah ctf_decl_sprintf (&cd, "enum %s", name); 78389513Sbmah break; 78489513Sbmah case CTF_K_FORWARD: 78589513Sbmah { 78689513Sbmah switch (ctf_type_kind_forwarded (fp, cdp->cd_type)) 78789513Sbmah { 78889513Sbmah case CTF_K_STRUCT: 78989513Sbmah ctf_decl_sprintf (&cd, "struct %s", name); 79089513Sbmah break; 79189513Sbmah case CTF_K_UNION: 79289513Sbmah ctf_decl_sprintf (&cd, "union %s", name); 79389513Sbmah break; 79489513Sbmah case CTF_K_ENUM: 79589513Sbmah ctf_decl_sprintf (&cd, "enum %s", name); 79689513Sbmah break; 79791515Sbmah default: 79876082Sbmah ctf_set_errno (fp, ECTF_CORRUPT); 79987993Sbmah ctf_decl_fini (&cd); 80076082Sbmah return NULL; 80176082Sbmah } 80276082Sbmah break; 80376082Sbmah } 80476082Sbmah case CTF_K_VOLATILE: 80576082Sbmah ctf_decl_sprintf (&cd, "volatile"); 80676082Sbmah break; 80776082Sbmah case CTF_K_CONST: 80876082Sbmah ctf_decl_sprintf (&cd, "const"); 80976082Sbmah break; 81076082Sbmah case CTF_K_RESTRICT: 81176082Sbmah ctf_decl_sprintf (&cd, "restrict"); 81276082Sbmah break; 81376082Sbmah case CTF_K_UNKNOWN: 81476082Sbmah if (name[0] == '\0') 81576082Sbmah ctf_decl_sprintf (&cd, _("(nonrepresentable type)")); 81676082Sbmah else 81776082Sbmah ctf_decl_sprintf (&cd, _("(nonrepresentable type %s)"), 81876082Sbmah name); 81976082Sbmah break; 82076082Sbmah } 82176082Sbmah 82276082Sbmah k = cdp->cd_kind; 82376082Sbmah } 82476082Sbmah 82576082Sbmah if (rp == prec) 82676082Sbmah ctf_decl_sprintf (&cd, ")"); 82776082Sbmah } 82876082Sbmah 82976082Sbmah if (cd.cd_enomem) 83076082Sbmah (void) ctf_set_errno (fp, ENOMEM); 83176082Sbmah 83276082Sbmah buf = ctf_decl_buf (&cd); 83376082Sbmah 83476082Sbmah ctf_decl_fini (&cd); 83576082Sbmah return buf; 83676082Sbmah} 83776082Sbmah 83887993Sbmah/* Lookup the given type ID and print a string name for it into buf. Return 83976082Sbmah the actual number of bytes (not including \0) needed to format the name. */ 84076082Sbmah 84176082Sbmahssize_t 84276082Sbmahctf_type_lname (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len) 84376082Sbmah{ 84476082Sbmah char *str = ctf_type_aname (fp, type); 84576082Sbmah size_t slen; 84687993Sbmah 84787993Sbmah if (str == NULL) 84887993Sbmah return CTF_ERR; /* errno is set for us. */ 84987993Sbmah 85087993Sbmah slen = strlen (str); 85187993Sbmah snprintf (buf, len, "%s", str); 85276082Sbmah free (str); 85376082Sbmah 85476082Sbmah if (slen >= len) 85576082Sbmah (void) ctf_set_errno (fp, ECTF_NAMELEN); 85676082Sbmah 85776082Sbmah return slen; 85876082Sbmah} 85976082Sbmah 86076082Sbmah/* Lookup the given type ID and print a string name for it into buf. If buf 86176082Sbmah is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us. */ 86276082Sbmah 86376082Sbmahchar * 86476082Sbmahctf_type_name (ctf_dict_t *fp, ctf_id_t type, char *buf, size_t len) 86576082Sbmah{ 86676082Sbmah ssize_t rv = ctf_type_lname (fp, type, buf, len); 86776082Sbmah return (rv >= 0 && (size_t) rv < len ? buf : NULL); 86876082Sbmah} 86976082Sbmah 87078626Sbmah/* Lookup the given type ID and return its raw, unadorned, undecorated name. 87178626Sbmah The name will live as long as its ctf_dict_t does. 87278626Sbmah 87378626Sbmah The only decoration is that a NULL return always means an error: nameless 87478626Sbmah types return a null string. */ 87578626Sbmah 87678626Sbmahconst char * 87776560Sbmahctf_type_name_raw (ctf_dict_t *fp, ctf_id_t type) 87887993Sbmah{ 87985745Sbmah const ctf_type_t *tp; 88085745Sbmah 88176082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 88285745Sbmah return NULL; /* errno is set for us. */ 88385745Sbmah 88485745Sbmah if (tp->ctt_name == 0) 88585745Sbmah return ""; 88685745Sbmah 88785745Sbmah return ctf_strraw (fp, tp->ctt_name); 88885745Sbmah} 88985745Sbmah 89085745Sbmah/* Lookup the given type ID and return its raw, unadorned, undecorated name as a 89176082Sbmah new dynamically-allocated string. */ 89285745Sbmah 89385745Sbmahchar * 89485745Sbmahctf_type_aname_raw (ctf_dict_t *fp, ctf_id_t type) 89585745Sbmah{ 89676082Sbmah const char *name = ctf_type_name_raw (fp, type); 89776082Sbmah 89885745Sbmah if (name != NULL) 89985745Sbmah return strdup (name); 90085745Sbmah 90185745Sbmah return NULL; 90276082Sbmah} 90376082Sbmah 90476082Sbmah/* Resolve the type down to a base type node, and then return the size 90576082Sbmah of the type storage in bytes. */ 90685745Sbmah 90785745Sbmahssize_t 90885745Sbmahctf_type_size (ctf_dict_t *fp, ctf_id_t type) 90985745Sbmah{ 91085745Sbmah ctf_dict_t *ofp = fp; 91185745Sbmah const ctf_type_t *tp; 91285745Sbmah ssize_t size; 91385745Sbmah ctf_arinfo_t ar; 91485745Sbmah 91585745Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 91685745Sbmah return -1; /* errno is set for us. */ 91785745Sbmah 91885745Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 91976082Sbmah return -1; /* errno is set for us. */ 92076082Sbmah 92176082Sbmah switch (LCTF_INFO_KIND (fp, tp->ctt_info)) 92285745Sbmah { 92385745Sbmah case CTF_K_POINTER: 92485745Sbmah return fp->ctf_dmodel->ctd_pointer; 92586896Sbmah 92685745Sbmah case CTF_K_FUNCTION: 92785745Sbmah return 0; /* Function size is only known by symtab. */ 92886896Sbmah 92985745Sbmah case CTF_K_ENUM: 93085745Sbmah return fp->ctf_dmodel->ctd_int; 93186896Sbmah 93285745Sbmah case CTF_K_ARRAY: 93385745Sbmah /* ctf_add_array() does not directly encode the element size, but 93486896Sbmah requires the user to multiply to determine the element size. 93585745Sbmah 93685745Sbmah If ctf_get_ctt_size() returns nonzero, then use the recorded 93786896Sbmah size instead. */ 93885745Sbmah 93985745Sbmah if ((size = ctf_get_ctt_size (fp, tp, NULL, NULL)) > 0) 94086896Sbmah return size; 94185745Sbmah 94285745Sbmah if (ctf_array_info (ofp, type, &ar) < 0 94386896Sbmah || (size = ctf_type_size (ofp, ar.ctr_contents)) < 0) 94485745Sbmah return -1; /* errno is set for us. */ 94585745Sbmah 94686896Sbmah return size * ar.ctr_nelems; 94785745Sbmah 94885745Sbmah case CTF_K_FORWARD: 94986896Sbmah /* Forwards do not have a meaningful size. */ 95085745Sbmah return (ctf_set_errno (ofp, ECTF_INCOMPLETE)); 95185745Sbmah 95286896Sbmah default: /* including slices of enums, etc */ 95385745Sbmah return (ctf_get_ctt_size (fp, tp, NULL, NULL)); 95485745Sbmah } 95586896Sbmah} 95685745Sbmah 95785745Sbmah/* Resolve the type down to a base type node, and then return the alignment 95886896Sbmah needed for the type storage in bytes. 95991513Sbmah 96085745Sbmah XXX may need arch-dependent attention. */ 96186896Sbmah 96285745Sbmahssize_t 96385745Sbmahctf_type_align (ctf_dict_t *fp, ctf_id_t type) 96486896Sbmah{ 96585745Sbmah const ctf_type_t *tp; 96685745Sbmah ctf_dict_t *ofp = fp; 96786896Sbmah int kind; 96885745Sbmah 96985745Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 97091513Sbmah return -1; /* errno is set for us. */ 97191513Sbmah 97291513Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 97386896Sbmah return -1; /* errno is set for us. */ 97491513Sbmah 97585745Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 97685745Sbmah switch (kind) 97786896Sbmah { 97885745Sbmah case CTF_K_POINTER: 97985745Sbmah case CTF_K_FUNCTION: 98086896Sbmah return fp->ctf_dmodel->ctd_pointer; 98185745Sbmah 98285745Sbmah case CTF_K_ARRAY: 98386896Sbmah { 98485745Sbmah ctf_arinfo_t r; 98585745Sbmah if (ctf_array_info (ofp, type, &r) < 0) 98686896Sbmah return -1; /* errno is set for us. */ 98785745Sbmah return (ctf_type_align (ofp, r.ctr_contents)); 98885745Sbmah } 98986896Sbmah 99085745Sbmah case CTF_K_STRUCT: 99185745Sbmah case CTF_K_UNION: 99286896Sbmah { 99385745Sbmah size_t align = 0; 99485745Sbmah ctf_dtdef_t *dtd; 99586896Sbmah unsigned char *vlen; 99685745Sbmah uint32_t i = 0, n = LCTF_INFO_VLEN (fp, tp->ctt_info); 99785745Sbmah ssize_t size, increment, vbytes; 99886896Sbmah 99985745Sbmah ctf_get_ctt_size (fp, tp, &size, &increment); 100085745Sbmah 100186896Sbmah if ((dtd = ctf_dynamic_type (fp, type)) != NULL) 100285745Sbmah { 100385745Sbmah vlen = dtd->dtd_vlen; 100486896Sbmah vbytes = dtd->dtd_vlen_alloc; 100585745Sbmah } 100685745Sbmah else 100785745Sbmah { 100885745Sbmah vlen = (unsigned char *) tp + increment; 100985745Sbmah vbytes = LCTF_VBYTES (fp, kind, size, n); 101076560Sbmah } 101176560Sbmah 101276560Sbmah if (kind == CTF_K_STRUCT) 101386896Sbmah n = MIN (n, 1); /* Only use first member for structs. */ 101476082Sbmah 101576082Sbmah for (; n != 0; n--, i++) 101676082Sbmah { 101776082Sbmah ctf_lmember_t memb; 101876082Sbmah 101976082Sbmah if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0) 102076082Sbmah return -1; /* errno is set for us. */ 102176082Sbmah 102276082Sbmah ssize_t am = ctf_type_align (ofp, memb.ctlm_type); 102376082Sbmah align = MAX (align, (size_t) am); 102476082Sbmah } 102576082Sbmah return align; 102680236Sbmah } 102780218Sbmah 102886076Smurray case CTF_K_ENUM: 102986076Smurray return fp->ctf_dmodel->ctd_int; 103086076Smurray 103180218Sbmah case CTF_K_FORWARD: 103276082Sbmah /* Forwards do not have a meaningful alignment. */ 103376082Sbmah return (ctf_set_errno (ofp, ECTF_INCOMPLETE)); 103476082Sbmah 103576082Sbmah default: /* including slices of enums, etc */ 103676082Sbmah return (ctf_get_ctt_size (fp, tp, NULL, NULL)); 103776082Sbmah } 103876082Sbmah} 103976082Sbmah 104076082Sbmah/* Return the kind (CTF_K_* constant) for the specified type ID. */ 104176082Sbmah 104276082Sbmahint 104376082Sbmahctf_type_kind_unsliced (ctf_dict_t *fp, ctf_id_t type) 104476082Sbmah{ 104576082Sbmah const ctf_type_t *tp; 104676082Sbmah 104776082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 104876082Sbmah return -1; /* errno is set for us. */ 104976082Sbmah 105076082Sbmah return (LCTF_INFO_KIND (fp, tp->ctt_info)); 105176082Sbmah} 105276082Sbmah 105376082Sbmah/* Return the kind (CTF_K_* constant) for the specified type ID. 105476082Sbmah Slices are considered to be of the same kind as the type sliced. */ 105586896Sbmah 105676082Sbmahint 105776082Sbmahctf_type_kind (ctf_dict_t *fp, ctf_id_t type) 105876082Sbmah{ 105976082Sbmah int kind; 106076082Sbmah 106176082Sbmah if ((kind = ctf_type_kind_unsliced (fp, type)) < 0) 106276082Sbmah return -1; 106376082Sbmah 106476082Sbmah if (kind == CTF_K_SLICE) 106576082Sbmah { 106676082Sbmah if ((type = ctf_type_reference (fp, type)) == CTF_ERR) 106776082Sbmah return -1; 106876082Sbmah kind = ctf_type_kind_unsliced (fp, type); 106976082Sbmah } 107076082Sbmah 107176082Sbmah return kind; 107286896Sbmah} 107376082Sbmah 107476082Sbmah/* Return the kind of this type, except, for forwards, return the kind of thing 107576082Sbmah this is a forward to. */ 107676082Sbmahint 107776082Sbmahctf_type_kind_forwarded (ctf_dict_t *fp, ctf_id_t type) 107876082Sbmah{ 107976082Sbmah int kind; 108076082Sbmah const ctf_type_t *tp; 108176082Sbmah 108276082Sbmah if ((kind = ctf_type_kind (fp, type)) < 0) 108376082Sbmah return -1; /* errno is set for us. */ 108476082Sbmah 108576082Sbmah if (kind != CTF_K_FORWARD) 108676082Sbmah return kind; 108776082Sbmah 108876082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 108976082Sbmah return -1; /* errno is set for us. */ 109076082Sbmah 109176082Sbmah return tp->ctt_type; 109276082Sbmah} 109376082Sbmah 109476082Sbmah/* If the type is one that directly references another type (such as POINTER), 109576082Sbmah then return the ID of the type to which it refers. */ 109676082Sbmah 109776082Sbmahctf_id_t 109876082Sbmahctf_type_reference (ctf_dict_t *fp, ctf_id_t type) 109986896Sbmah{ 110076082Sbmah ctf_dict_t *ofp = fp; 110176082Sbmah const ctf_type_t *tp; 110276082Sbmah 110376082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 110476082Sbmah return CTF_ERR; /* errno is set for us. */ 110576082Sbmah 110676082Sbmah switch (LCTF_INFO_KIND (fp, tp->ctt_info)) 110776082Sbmah { 110886896Sbmah case CTF_K_POINTER: 110976082Sbmah case CTF_K_TYPEDEF: 111076082Sbmah case CTF_K_VOLATILE: 111176082Sbmah case CTF_K_CONST: 111276082Sbmah case CTF_K_RESTRICT: 111376082Sbmah return tp->ctt_type; 111476082Sbmah /* Slices store their type in an unusual place. */ 111576082Sbmah case CTF_K_SLICE: 111686896Sbmah { 111776082Sbmah ctf_dtdef_t *dtd; 111876082Sbmah const ctf_slice_t *sp; 111976082Sbmah 112076082Sbmah if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) 112176082Sbmah { 112276082Sbmah ssize_t increment; 112376082Sbmah 112476082Sbmah (void) ctf_get_ctt_size (fp, tp, NULL, &increment); 112576082Sbmah sp = (const ctf_slice_t *) ((uintptr_t) tp + increment); 112676082Sbmah } 112776082Sbmah else 112876082Sbmah sp = (const ctf_slice_t *) dtd->dtd_vlen; 112976082Sbmah 113076082Sbmah return sp->cts_type; 113186896Sbmah } 113289327Sbmah default: 113389327Sbmah return (ctf_set_errno (ofp, ECTF_NOTREF)); 113489327Sbmah } 113590036Sbmah} 113689327Sbmah 113789327Sbmah/* Find a pointer to type by looking in fp->ctf_ptrtab. If we can't find a 113889327Sbmah pointer to the given type, see if we can compute a pointer to the type 113976082Sbmah resulting from resolving the type down to its base type and use that 114086896Sbmah instead. This helps with cases where the CTF data includes "struct foo *" 114176560Sbmah but not "foo_t *" and the user accesses "foo_t *" in the debugger. 114276082Sbmah 114376082Sbmah XXX what about parent dicts? */ 114476082Sbmah 114576082Sbmahctf_id_t 114676082Sbmahctf_type_pointer (ctf_dict_t *fp, ctf_id_t type) 114776082Sbmah{ 114876082Sbmah ctf_dict_t *ofp = fp; 114976082Sbmah ctf_id_t ntype; 115076082Sbmah 115176082Sbmah if (ctf_lookup_by_id (&fp, type) == NULL) 115287993Sbmah return CTF_ERR; /* errno is set for us. */ 115393404Skeramida 115476498Sbmah if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0) 115576498Sbmah return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD))); 115676498Sbmah 115776498Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 115883455Sbmah return (ctf_set_errno (ofp, ECTF_NOTYPE)); 115983455Sbmah 116083455Sbmah if (ctf_lookup_by_id (&fp, type) == NULL) 116183455Sbmah return (ctf_set_errno (ofp, ECTF_NOTYPE)); 116276498Sbmah 116376498Sbmah if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX (fp, type)]) != 0) 116476498Sbmah return (LCTF_INDEX_TO_TYPE (fp, ntype, (fp->ctf_flags & LCTF_CHILD))); 116576498Sbmah 116676498Sbmah return (ctf_set_errno (ofp, ECTF_NOTYPE)); 116776498Sbmah} 116876498Sbmah 116979638Sbmah/* Return the encoding for the specified INTEGER, FLOAT, or ENUM. */ 117079638Sbmah 117179638Sbmahint 117279638Sbmahctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep) 117379638Sbmah{ 117479638Sbmah ctf_dict_t *ofp = fp; 117576498Sbmah ctf_dtdef_t *dtd; 117676498Sbmah const ctf_type_t *tp; 117779638Sbmah ssize_t increment; 117879638Sbmah const unsigned char *vlen; 117979638Sbmah uint32_t data; 118083455Sbmah 118183455Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 118283455Sbmah return -1; /* errno is set for us. */ 118383455Sbmah 118476498Sbmah if ((dtd = ctf_dynamic_type (ofp, type)) != NULL) 118576498Sbmah vlen = dtd->dtd_vlen; 118676498Sbmah else 118786896Sbmah { 118876082Sbmah ctf_get_ctt_size (fp, tp, NULL, &increment); 118976082Sbmah vlen = (const unsigned char *) ((uintptr_t) tp + increment); 119076082Sbmah } 119176082Sbmah 119276082Sbmah switch (LCTF_INFO_KIND (fp, tp->ctt_info)) 119376082Sbmah { 119476082Sbmah case CTF_K_INTEGER: 119576082Sbmah data = *(const uint32_t *) vlen; 119693404Skeramida ep->cte_format = CTF_INT_ENCODING (data); 119776082Sbmah ep->cte_offset = CTF_INT_OFFSET (data); 119876082Sbmah ep->cte_bits = CTF_INT_BITS (data); 119976082Sbmah break; 120076082Sbmah case CTF_K_FLOAT: 120176082Sbmah data = *(const uint32_t *) vlen; 120276082Sbmah ep->cte_format = CTF_FP_ENCODING (data); 120376082Sbmah ep->cte_offset = CTF_FP_OFFSET (data); 120476082Sbmah ep->cte_bits = CTF_FP_BITS (data); 120576082Sbmah break; 120676082Sbmah case CTF_K_ENUM: 120776082Sbmah /* v3 only: we must guess at the underlying integral format. */ 120876152Sbmah ep->cte_format = CTF_INT_SIGNED; 120976082Sbmah ep->cte_offset = 0; 121076082Sbmah ep->cte_bits = 0; 121176152Sbmah break; 121276082Sbmah case CTF_K_SLICE: 121376082Sbmah { 121476082Sbmah const ctf_slice_t *slice; 121576082Sbmah ctf_encoding_t underlying_en; 121676082Sbmah ctf_id_t underlying; 121776082Sbmah 121876082Sbmah slice = (ctf_slice_t *) vlen; 121986896Sbmah underlying = ctf_type_resolve (fp, slice->cts_type); 122076082Sbmah if (ctf_type_encoding (fp, underlying, &underlying_en) < 0) 122176082Sbmah return -1; /* errno is set for us. */ 122286896Sbmah 122376082Sbmah ep->cte_format = underlying_en.cte_format; 122476082Sbmah ep->cte_offset = slice->cts_offset; 122586896Sbmah ep->cte_bits = slice->cts_bits; 122686896Sbmah break; 122786896Sbmah } 122876082Sbmah default: 122976082Sbmah return (ctf_set_errno (ofp, ECTF_NOTINTFP)); 123076082Sbmah } 123176082Sbmah 123276082Sbmah return 0; 123376082Sbmah} 123476082Sbmah 123576082Sbmahint 123676082Sbmahctf_type_cmp (ctf_dict_t *lfp, ctf_id_t ltype, ctf_dict_t *rfp, 123776082Sbmah ctf_id_t rtype) 123876082Sbmah{ 123976082Sbmah int rval; 124076082Sbmah 124176082Sbmah if (ltype < rtype) 124276082Sbmah rval = -1; 124376082Sbmah else if (ltype > rtype) 124476082Sbmah rval = 1; 124576082Sbmah else 124676082Sbmah rval = 0; 124776082Sbmah 124886896Sbmah if (lfp == rfp) 124976560Sbmah return rval; 125076082Sbmah 125186896Sbmah if (LCTF_TYPE_ISPARENT (lfp, ltype) && lfp->ctf_parent != NULL) 125276560Sbmah lfp = lfp->ctf_parent; 125376082Sbmah 125476082Sbmah if (LCTF_TYPE_ISPARENT (rfp, rtype) && rfp->ctf_parent != NULL) 125576082Sbmah rfp = rfp->ctf_parent; 125676082Sbmah 125776082Sbmah if (lfp < rfp) 125876082Sbmah return -1; 125976082Sbmah 126086896Sbmah if (lfp > rfp) 126176082Sbmah return 1; 126276082Sbmah 126376082Sbmah return rval; 126476082Sbmah} 126576082Sbmah 126676082Sbmah/* Return a boolean value indicating if two types are compatible. This function 126776082Sbmah returns true if the two types are the same, or if they (or their ultimate 126876082Sbmah base type) have the same encoding properties, or (for structs / unions / 126976082Sbmah enums / forward declarations) if they have the same name and (for structs / 127076082Sbmah unions) member count. */ 127176082Sbmah 127276082Sbmahint 127376082Sbmahctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype, 127476082Sbmah ctf_dict_t *rfp, ctf_id_t rtype) 127576082Sbmah{ 127676082Sbmah const ctf_type_t *ltp, *rtp; 127776082Sbmah ctf_encoding_t le, re; 127876082Sbmah ctf_arinfo_t la, ra; 127976082Sbmah uint32_t lkind, rkind; 128086896Sbmah int same_names = 0; 128176082Sbmah 128276082Sbmah if (ctf_type_cmp (lfp, ltype, rfp, rtype) == 0) 128376082Sbmah return 1; 128476082Sbmah 128576082Sbmah ltype = ctf_type_resolve (lfp, ltype); 128676082Sbmah lkind = ctf_type_kind (lfp, ltype); 128776082Sbmah 128876082Sbmah rtype = ctf_type_resolve (rfp, rtype); 128976082Sbmah rkind = ctf_type_kind (rfp, rtype); 129076082Sbmah 129176082Sbmah ltp = ctf_lookup_by_id (&lfp, ltype); 129276082Sbmah rtp = ctf_lookup_by_id (&rfp, rtype); 129376082Sbmah 129476082Sbmah if (ltp != NULL && rtp != NULL) 129576082Sbmah same_names = (strcmp (ctf_strptr (lfp, ltp->ctt_name), 129676082Sbmah ctf_strptr (rfp, rtp->ctt_name)) == 0); 129786896Sbmah 129876082Sbmah if (((lkind == CTF_K_ENUM) && (rkind == CTF_K_INTEGER)) || 129976082Sbmah ((rkind == CTF_K_ENUM) && (lkind == CTF_K_INTEGER))) 130076082Sbmah return 1; 130176082Sbmah 130276082Sbmah if (lkind != rkind) 130376082Sbmah return 0; 130476757Sbmah 130576757Sbmah switch (lkind) 130676757Sbmah { 130776082Sbmah case CTF_K_INTEGER: 130876082Sbmah case CTF_K_FLOAT: 130976082Sbmah memset (&le, 0, sizeof (le)); 131076082Sbmah memset (&re, 0, sizeof (re)); 131176082Sbmah return (ctf_type_encoding (lfp, ltype, &le) == 0 131276082Sbmah && ctf_type_encoding (rfp, rtype, &re) == 0 131376082Sbmah && memcmp (&le, &re, sizeof (ctf_encoding_t)) == 0); 131476082Sbmah case CTF_K_POINTER: 131576082Sbmah return (ctf_type_compat (lfp, ctf_type_reference (lfp, ltype), 131676082Sbmah rfp, ctf_type_reference (rfp, rtype))); 131776082Sbmah case CTF_K_ARRAY: 131876082Sbmah return (ctf_array_info (lfp, ltype, &la) == 0 131976082Sbmah && ctf_array_info (rfp, rtype, &ra) == 0 132076082Sbmah && la.ctr_nelems == ra.ctr_nelems 132176082Sbmah && ctf_type_compat (lfp, la.ctr_contents, rfp, ra.ctr_contents) 132276082Sbmah && ctf_type_compat (lfp, la.ctr_index, rfp, ra.ctr_index)); 132376082Sbmah case CTF_K_STRUCT: 132476082Sbmah case CTF_K_UNION: 132576082Sbmah return (same_names && (ctf_type_size (lfp, ltype) 132676082Sbmah == ctf_type_size (rfp, rtype))); 132776082Sbmah case CTF_K_ENUM: 132876082Sbmah { 132976082Sbmah int lencoded, rencoded; 133076082Sbmah lencoded = ctf_type_encoding (lfp, ltype, &le); 133176082Sbmah rencoded = ctf_type_encoding (rfp, rtype, &re); 133276082Sbmah 133376082Sbmah if ((lencoded != rencoded) || 133476082Sbmah ((lencoded == 0) && memcmp (&le, &re, sizeof (ctf_encoding_t)) != 0)) 133576082Sbmah return 0; 133676082Sbmah } 133776082Sbmah /* FALLTHRU */ 133876082Sbmah case CTF_K_FORWARD: 133986896Sbmah return same_names; /* No other checks required for these type kinds. */ 134076082Sbmah default: 134176082Sbmah return 0; /* Should not get here since we did a resolve. */ 134276082Sbmah } 134376082Sbmah} 134476082Sbmah 134576082Sbmah/* Return the number of members in a STRUCT or UNION, or the number of 134676082Sbmah enumerators in an ENUM. The count does not include unnamed sub-members. */ 134776082Sbmah 134876082Sbmahint 134976082Sbmahctf_member_count (ctf_dict_t *fp, ctf_id_t type) 135085666Sbmah{ 135185666Sbmah ctf_dict_t *ofp = fp; 135285666Sbmah const ctf_type_t *tp; 135385666Sbmah uint32_t kind; 135485666Sbmah 135585666Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 135685666Sbmah return -1; /* errno is set for us. */ 135785666Sbmah 135885666Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 135985666Sbmah return -1; /* errno is set for us. */ 136076082Sbmah 136186896Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 136276082Sbmah 136376082Sbmah if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM) 136476082Sbmah return (ctf_set_errno (ofp, ECTF_NOTSUE)); 136576082Sbmah 136676082Sbmah return LCTF_INFO_VLEN (fp, tp->ctt_info); 136776082Sbmah} 136876082Sbmah 136976082Sbmah/* Return the type and offset for a given member of a STRUCT or UNION. */ 137076082Sbmah 137176082Sbmahint 137276082Sbmahctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, 137376082Sbmah ctf_membinfo_t *mip) 137476082Sbmah{ 137576082Sbmah ctf_dict_t *ofp = fp; 137676082Sbmah const ctf_type_t *tp; 137776082Sbmah ctf_dtdef_t *dtd; 137876082Sbmah unsigned char *vlen; 137976082Sbmah ssize_t size, increment, vbytes; 138076082Sbmah uint32_t kind, n, i = 0; 138176082Sbmah 138286896Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 138376082Sbmah return -1; /* errno is set for us. */ 138476082Sbmah 138586896Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 138676082Sbmah return -1; /* errno is set for us. */ 138776082Sbmah 138876082Sbmah ctf_get_ctt_size (fp, tp, &size, &increment); 138976082Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 139076082Sbmah 139176082Sbmah if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 139276082Sbmah return (ctf_set_errno (ofp, ECTF_NOTSOU)); 139376082Sbmah 139476082Sbmah n = LCTF_INFO_VLEN (fp, tp->ctt_info); 139576082Sbmah if ((dtd = ctf_dynamic_type (fp, type)) != NULL) 139676082Sbmah { 139776082Sbmah vlen = dtd->dtd_vlen; 139876082Sbmah vbytes = dtd->dtd_vlen_alloc; 139976082Sbmah } 140076082Sbmah else 140176082Sbmah { 140286896Sbmah vlen = (unsigned char *) tp + increment; 140376082Sbmah vbytes = LCTF_VBYTES (fp, kind, size, n); 140476082Sbmah } 140576082Sbmah 140676082Sbmah for (; n != 0; n--, i++) 140776082Sbmah { 140876082Sbmah ctf_lmember_t memb; 140976082Sbmah const char *membname; 141088859Sbmah 141188859Sbmah if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0) 141288859Sbmah return -1; /* errno is set for us. */ 141388859Sbmah 141476560Sbmah membname = ctf_strptr (fp, memb.ctlm_name); 141576082Sbmah 141676082Sbmah if (membname[0] == 0 141776082Sbmah && (ctf_type_kind (fp, memb.ctlm_type) == CTF_K_STRUCT 141876082Sbmah || ctf_type_kind (fp, memb.ctlm_type) == CTF_K_UNION) 141976082Sbmah && (ctf_member_info (fp, memb.ctlm_type, name, mip) == 0)) 142076082Sbmah return 0; 142176082Sbmah 142276082Sbmah if (strcmp (membname, name) == 0) 142376082Sbmah { 142476082Sbmah mip->ctm_type = memb.ctlm_type; 142576082Sbmah mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (&memb); 142676082Sbmah return 0; 142776082Sbmah } 142876082Sbmah } 142976082Sbmah 143076082Sbmah return (ctf_set_errno (ofp, ECTF_NOMEMBNAM)); 143176082Sbmah} 143276082Sbmah 143376082Sbmah/* Return the array type, index, and size information for the specified ARRAY. */ 143476082Sbmah 143576082Sbmahint 143676082Sbmahctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp) 143776082Sbmah{ 143876082Sbmah ctf_dict_t *ofp = fp; 143976082Sbmah const ctf_type_t *tp; 144076082Sbmah const ctf_array_t *ap; 144176082Sbmah const ctf_dtdef_t *dtd; 144276082Sbmah ssize_t increment; 144376082Sbmah 144476082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 144587808Sbmah return -1; /* errno is set for us. */ 144676082Sbmah 144785666Sbmah if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ARRAY) 144885666Sbmah return (ctf_set_errno (ofp, ECTF_NOTARRAY)); 144976082Sbmah 145085666Sbmah if ((dtd = ctf_dynamic_type (ofp, type)) != NULL) 145185666Sbmah ap = (const ctf_array_t *) dtd->dtd_vlen; 145285666Sbmah else 145385666Sbmah { 145485666Sbmah ctf_get_ctt_size (fp, tp, NULL, &increment); 145585666Sbmah ap = (const ctf_array_t *) ((uintptr_t) tp + increment); 145685666Sbmah } 145785666Sbmah arp->ctr_contents = ap->cta_contents; 145885666Sbmah arp->ctr_index = ap->cta_index; 145985666Sbmah arp->ctr_nelems = ap->cta_nelems; 146085666Sbmah 146186896Sbmah return 0; 146285666Sbmah} 146376082Sbmah 146489513Sbmah/* Convert the specified value to the corresponding enum tag name, if a 146589513Sbmah matching name can be found. Otherwise NULL is returned. */ 146689513Sbmah 146785666Sbmahconst char * 146885666Sbmahctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value) 146985666Sbmah{ 147085666Sbmah ctf_dict_t *ofp = fp; 147185666Sbmah const ctf_type_t *tp; 147285666Sbmah const ctf_enum_t *ep; 147385666Sbmah const ctf_dtdef_t *dtd; 147476082Sbmah ssize_t increment; 147576082Sbmah uint32_t n; 147685666Sbmah 147776082Sbmah if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR) 147876082Sbmah return NULL; /* errno is set for us. */ 147985666Sbmah 148076082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 148185666Sbmah return NULL; /* errno is set for us. */ 148285666Sbmah 148385666Sbmah if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM) 148485666Sbmah { 148585666Sbmah ctf_set_errno (ofp, ECTF_NOTENUM); 148685666Sbmah return NULL; 148776082Sbmah } 148876082Sbmah 148976082Sbmah ctf_get_ctt_size (fp, tp, NULL, &increment); 149085666Sbmah 149176082Sbmah if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) 149276082Sbmah ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); 149385666Sbmah else 149476082Sbmah ep = (const ctf_enum_t *) dtd->dtd_vlen; 149585666Sbmah 149685666Sbmah for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) 149776082Sbmah { 149876082Sbmah if (ep->cte_value == value) 149985666Sbmah return (ctf_strptr (fp, ep->cte_name)); 150076082Sbmah } 150189513Sbmah 150289513Sbmah ctf_set_errno (ofp, ECTF_NOENUMNAM); 150389513Sbmah return NULL; 150485666Sbmah} 150589513Sbmah 150685666Sbmah/* Convert the specified enum tag name to the corresponding value, if a 150776082Sbmah matching name can be found. Otherwise CTF_ERR is returned. */ 150889513Sbmah 150989513Sbmahint 151089513Sbmahctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp) 151189513Sbmah{ 151289513Sbmah ctf_dict_t *ofp = fp; 151389513Sbmah const ctf_type_t *tp; 151489513Sbmah const ctf_enum_t *ep; 151589513Sbmah const ctf_dtdef_t *dtd; 151689513Sbmah ssize_t increment; 151785666Sbmah uint32_t n; 151885666Sbmah 151985666Sbmah if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR) 152085666Sbmah return -1; /* errno is set for us. */ 152185666Sbmah 152285666Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 152385666Sbmah return -1; /* errno is set for us. */ 152485666Sbmah 152585666Sbmah if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM) 152685666Sbmah { 152776082Sbmah (void) ctf_set_errno (ofp, ECTF_NOTENUM); 152885666Sbmah return -1; 152985666Sbmah } 153076082Sbmah 153185666Sbmah ctf_get_ctt_size (fp, tp, NULL, &increment); 153285666Sbmah 153376082Sbmah if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) 153476082Sbmah ep = (const ctf_enum_t *) ((uintptr_t) tp + increment); 153585666Sbmah else 153676082Sbmah ep = (const ctf_enum_t *) dtd->dtd_vlen; 153785666Sbmah 153885666Sbmah for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++) 153985666Sbmah { 154085710Sbmah if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0) 154185710Sbmah { 154285710Sbmah if (valp != NULL) 154385710Sbmah *valp = ep->cte_value; 154485710Sbmah return 0; 154585710Sbmah } 154685710Sbmah } 154785710Sbmah 154885710Sbmah ctf_set_errno (ofp, ECTF_NOENUMNAM); 154985710Sbmah return -1; 155085710Sbmah} 155185710Sbmah 155285710Sbmah/* Given a type ID relating to a function type, return info on return types and 155385710Sbmah arg counts for that function. */ 155485710Sbmah 155585666Sbmahint 155685666Sbmahctf_func_type_info (ctf_dict_t *fp, ctf_id_t type, ctf_funcinfo_t *fip) 155785666Sbmah{ 155885710Sbmah const ctf_type_t *tp; 155985710Sbmah uint32_t kind; 156085710Sbmah const uint32_t *args; 156185710Sbmah const ctf_dtdef_t *dtd; 156285710Sbmah ssize_t size, increment; 156385710Sbmah 156485710Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 156585710Sbmah return -1; /* errno is set for us. */ 156685710Sbmah 156785710Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 156885710Sbmah return -1; /* errno is set for us. */ 156985710Sbmah 157085710Sbmah (void) ctf_get_ctt_size (fp, tp, &size, &increment); 157185710Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 157276560Sbmah 157376560Sbmah if (kind != CTF_K_FUNCTION) 157476082Sbmah return (ctf_set_errno (fp, ECTF_NOTFUNC)); 157576082Sbmah 157676082Sbmah fip->ctc_return = tp->ctt_type; 157776082Sbmah fip->ctc_flags = 0; 157876082Sbmah fip->ctc_argc = LCTF_INFO_VLEN (fp, tp->ctt_info); 157976082Sbmah 158076082Sbmah if ((dtd = ctf_dynamic_type (fp, type)) == NULL) 158176560Sbmah args = (uint32_t *) ((uintptr_t) tp + increment); 158276560Sbmah else 158376082Sbmah args = (uint32_t *) dtd->dtd_vlen; 158476082Sbmah 158576082Sbmah if (fip->ctc_argc != 0 && args[fip->ctc_argc - 1] == 0) 158676082Sbmah { 158776082Sbmah fip->ctc_flags |= CTF_FUNC_VARARG; 158876082Sbmah fip->ctc_argc--; 158976082Sbmah } 159076082Sbmah 159176082Sbmah return 0; 159276082Sbmah} 159376082Sbmah 159476082Sbmah/* Given a type ID relating to a function type, return the arguments for the 159576082Sbmah function. */ 159676082Sbmah 159776082Sbmahint 159876082Sbmahctf_func_type_args (ctf_dict_t *fp, ctf_id_t type, uint32_t argc, ctf_id_t *argv) 159976082Sbmah{ 160076082Sbmah const ctf_type_t *tp; 160176082Sbmah const uint32_t *args; 160276082Sbmah const ctf_dtdef_t *dtd; 160376082Sbmah ssize_t size, increment; 160476082Sbmah ctf_funcinfo_t f; 160576560Sbmah 160676560Sbmah if (ctf_func_type_info (fp, type, &f) < 0) 160776082Sbmah return -1; /* errno is set for us. */ 160876082Sbmah 160991637Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) 161076082Sbmah return -1; /* errno is set for us. */ 161176082Sbmah 161276082Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 161376082Sbmah return -1; /* errno is set for us. */ 161476082Sbmah 161576082Sbmah (void) ctf_get_ctt_size (fp, tp, &size, &increment); 161691637Sbmah 161776082Sbmah if ((dtd = ctf_dynamic_type (fp, type)) == NULL) 161876082Sbmah args = (uint32_t *) ((uintptr_t) tp + increment); 161976082Sbmah else 162076082Sbmah args = (uint32_t *) dtd->dtd_vlen; 162176082Sbmah 162276082Sbmah for (argc = MIN (argc, f.ctc_argc); argc != 0; argc--) 162376082Sbmah *argv++ = *args++; 162476082Sbmah 162576082Sbmah return 0; 162676082Sbmah} 162776082Sbmah 162876082Sbmah/* Recursively visit the members of any type. This function is used as the 162976082Sbmah engine for ctf_type_visit, below. We resolve the input type, recursively 163076082Sbmah invoke ourself for each type member if the type is a struct or union, and 163176082Sbmah then invoke the callback function on the current type. If any callback 163276082Sbmah returns non-zero, we abort and percolate the error code back up to the top. */ 163376082Sbmah 163476082Sbmahstatic int 163576082Sbmahctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func, 163676082Sbmah void *arg, const char *name, unsigned long offset, int depth) 163776082Sbmah{ 163876560Sbmah ctf_id_t otype = type; 163976560Sbmah const ctf_type_t *tp; 164076082Sbmah const ctf_dtdef_t *dtd; 164176082Sbmah unsigned char *vlen; 164276082Sbmah ssize_t size, increment, vbytes; 164376082Sbmah uint32_t kind, n, i = 0; 164476082Sbmah int nonrepresentable = 0; 164576082Sbmah int rc; 164676082Sbmah 164776082Sbmah if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) { 164876082Sbmah if (ctf_errno (fp) != ECTF_NONREPRESENTABLE) 164976082Sbmah return -1; /* errno is set for us. */ 165087993Sbmah else 165177590Sbmah nonrepresentable = 1; 165277590Sbmah } 165377590Sbmah 165480218Sbmah if (!nonrepresentable) 165577590Sbmah if ((tp = ctf_lookup_by_id (&fp, type)) == NULL) 165677590Sbmah return -1; /* errno is set for us. */ 165777590Sbmah 165877590Sbmah if ((rc = func (name, otype, offset, depth, arg)) != 0) 165977590Sbmah return rc; 166077590Sbmah 166177590Sbmah if (!nonrepresentable) 166286896Sbmah kind = LCTF_INFO_KIND (fp, tp->ctt_info); 166380242Sbmah 166480242Sbmah if (nonrepresentable || (kind != CTF_K_STRUCT && kind != CTF_K_UNION)) 166580242Sbmah return 0; 166680242Sbmah 166780242Sbmah ctf_get_ctt_size (fp, tp, &size, &increment); 166880242Sbmah 166980242Sbmah n = LCTF_INFO_VLEN (fp, tp->ctt_info); 167080242Sbmah if ((dtd = ctf_dynamic_type (fp, type)) != NULL) 167180242Sbmah { 167280242Sbmah vlen = dtd->dtd_vlen; 167380242Sbmah vbytes = dtd->dtd_vlen_alloc; 167480242Sbmah } 167580242Sbmah else 167680242Sbmah { 167780242Sbmah vlen = (unsigned char *) tp + increment; 167880242Sbmah vbytes = LCTF_VBYTES (fp, kind, size, n); 167980242Sbmah } 168080242Sbmah 168180242Sbmah for (; n != 0; n--, i++) 168280242Sbmah { 168380242Sbmah ctf_lmember_t memb; 168480242Sbmah 168580242Sbmah if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0) 168686896Sbmah return -1; /* errno is set for us. */ 168785163Sbmah 168884065Sbmah if ((rc = ctf_type_rvisit (fp, memb.ctlm_type, 168984065Sbmah func, arg, ctf_strptr (fp, memb.ctlm_name), 169093821Sbmah offset + (unsigned long) CTF_LMEM_OFFSET (&memb), 169184065Sbmah depth + 1)) != 0) 169284065Sbmah return rc; 169389836Sjdp } 169489836Sjdp 169589836Sjdp return 0; 169684065Sbmah} 169784065Sbmah 169884065Sbmah/* Recursively visit the members of any type. We pass the name, member 169984065Sbmah type, and offset of each member to the specified callback function. */ 170084065Sbmahint 170184065Sbmahctf_type_visit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg) 170284065Sbmah{ 170384065Sbmah return (ctf_type_rvisit (fp, type, func, arg, "", 0, 0)); 170485163Sbmah} 170587993Sbmah