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