xref: /netbsd-src/external/gpl3/gdb.old/dist/libctf/ctf-create.c (revision 6881a4007f077b54e5f51159c52b9b25f57deb0d)
1*6881a400Schristos /* CTF dict creation.
2*6881a400Schristos    Copyright (C) 2019-2022 Free Software Foundation, Inc.
37d62b00eSchristos 
47d62b00eSchristos    This file is part of libctf.
57d62b00eSchristos 
67d62b00eSchristos    libctf is free software; you can redistribute it and/or modify it under
77d62b00eSchristos    the terms of the GNU General Public License as published by the Free
87d62b00eSchristos    Software Foundation; either version 3, or (at your option) any later
97d62b00eSchristos    version.
107d62b00eSchristos 
117d62b00eSchristos    This program is distributed in the hope that it will be useful, but
127d62b00eSchristos    WITHOUT ANY WARRANTY; without even the implied warranty of
137d62b00eSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
147d62b00eSchristos    See the GNU General Public License for more details.
157d62b00eSchristos 
167d62b00eSchristos    You should have received a copy of the GNU General Public License
177d62b00eSchristos    along with this program; see the file COPYING.  If not see
187d62b00eSchristos    <http://www.gnu.org/licenses/>.  */
197d62b00eSchristos 
207d62b00eSchristos #include <ctf-impl.h>
217d62b00eSchristos #include <sys/param.h>
227d62b00eSchristos #include <string.h>
237d62b00eSchristos #include <unistd.h>
247d62b00eSchristos 
257d62b00eSchristos #ifndef EOVERFLOW
267d62b00eSchristos #define EOVERFLOW ERANGE
277d62b00eSchristos #endif
287d62b00eSchristos 
297d62b00eSchristos #ifndef roundup
307d62b00eSchristos #define roundup(x, y)  ((((x) + ((y) - 1)) / (y)) * (y))
317d62b00eSchristos #endif
327d62b00eSchristos 
33*6881a400Schristos /* The initial size of a dynamic type's vlen in members.  Arbitrary: the bigger
34*6881a400Schristos    this is, the less allocation needs to be done for small structure
35*6881a400Schristos    initialization, and the more memory is wasted for small structures during CTF
36*6881a400Schristos    construction.  No effect on generated CTF or ctf_open()ed CTF. */
37*6881a400Schristos #define INITIAL_VLEN 16
38*6881a400Schristos 
397d62b00eSchristos /* Make sure the ptrtab has enough space for at least one more type.
407d62b00eSchristos 
417d62b00eSchristos    We start with 4KiB of ptrtab, enough for a thousand types, then grow it 25%
427d62b00eSchristos    at a time.  */
437d62b00eSchristos 
447d62b00eSchristos static int
45*6881a400Schristos ctf_grow_ptrtab (ctf_dict_t *fp)
467d62b00eSchristos {
477d62b00eSchristos   size_t new_ptrtab_len = fp->ctf_ptrtab_len;
487d62b00eSchristos 
497d62b00eSchristos   /* We allocate one more ptrtab entry than we need, for the initial zero,
507d62b00eSchristos      plus one because the caller will probably allocate a new type.  */
517d62b00eSchristos 
527d62b00eSchristos   if (fp->ctf_ptrtab == NULL)
537d62b00eSchristos     new_ptrtab_len = 1024;
547d62b00eSchristos   else if ((fp->ctf_typemax + 2) > fp->ctf_ptrtab_len)
557d62b00eSchristos     new_ptrtab_len = fp->ctf_ptrtab_len * 1.25;
567d62b00eSchristos 
577d62b00eSchristos   if (new_ptrtab_len != fp->ctf_ptrtab_len)
587d62b00eSchristos     {
597d62b00eSchristos       uint32_t *new_ptrtab;
607d62b00eSchristos 
617d62b00eSchristos       if ((new_ptrtab = realloc (fp->ctf_ptrtab,
627d62b00eSchristos 				 new_ptrtab_len * sizeof (uint32_t))) == NULL)
637d62b00eSchristos 	return (ctf_set_errno (fp, ENOMEM));
647d62b00eSchristos 
657d62b00eSchristos       fp->ctf_ptrtab = new_ptrtab;
667d62b00eSchristos       memset (fp->ctf_ptrtab + fp->ctf_ptrtab_len, 0,
677d62b00eSchristos 	      (new_ptrtab_len - fp->ctf_ptrtab_len) * sizeof (uint32_t));
687d62b00eSchristos       fp->ctf_ptrtab_len = new_ptrtab_len;
697d62b00eSchristos     }
707d62b00eSchristos   return 0;
717d62b00eSchristos }
727d62b00eSchristos 
73*6881a400Schristos /* Make sure a vlen has enough space: expand it otherwise.  Unlike the ptrtab,
74*6881a400Schristos    which grows quite slowly, the vlen grows in big jumps because it is quite
75*6881a400Schristos    expensive to expand: the caller has to scan the old vlen for string refs
76*6881a400Schristos    first and remove them, then re-add them afterwards.  The initial size is
77*6881a400Schristos    more or less arbitrary.  */
78*6881a400Schristos static int
79*6881a400Schristos ctf_grow_vlen (ctf_dict_t *fp, ctf_dtdef_t *dtd, size_t vlen)
80*6881a400Schristos {
81*6881a400Schristos   unsigned char *old = dtd->dtd_vlen;
82*6881a400Schristos 
83*6881a400Schristos   if (dtd->dtd_vlen_alloc > vlen)
84*6881a400Schristos     return 0;
85*6881a400Schristos 
86*6881a400Schristos   if ((dtd->dtd_vlen = realloc (dtd->dtd_vlen,
87*6881a400Schristos 				dtd->dtd_vlen_alloc * 2)) == NULL)
88*6881a400Schristos     {
89*6881a400Schristos       dtd->dtd_vlen = old;
90*6881a400Schristos       return (ctf_set_errno (fp, ENOMEM));
91*6881a400Schristos     }
92*6881a400Schristos   memset (dtd->dtd_vlen + dtd->dtd_vlen_alloc, 0, dtd->dtd_vlen_alloc);
93*6881a400Schristos   dtd->dtd_vlen_alloc *= 2;
94*6881a400Schristos   return 0;
95*6881a400Schristos }
96*6881a400Schristos 
97*6881a400Schristos /* To create an empty CTF dict, we just declare a zeroed header and call
98*6881a400Schristos    ctf_bufopen() on it.  If ctf_bufopen succeeds, we mark the new dict r/w and
99*6881a400Schristos    initialize the dynamic members.  We start assigning type IDs at 1 because
1007d62b00eSchristos    type ID 0 is used as a sentinel and a not-found indicator.  */
1017d62b00eSchristos 
102*6881a400Schristos ctf_dict_t *
1037d62b00eSchristos ctf_create (int *errp)
1047d62b00eSchristos {
1057d62b00eSchristos   static const ctf_header_t hdr = { .cth_preamble = { CTF_MAGIC, CTF_VERSION, 0 } };
1067d62b00eSchristos 
1077d62b00eSchristos   ctf_dynhash_t *dthash;
1087d62b00eSchristos   ctf_dynhash_t *dvhash;
1097d62b00eSchristos   ctf_dynhash_t *structs = NULL, *unions = NULL, *enums = NULL, *names = NULL;
110*6881a400Schristos   ctf_dynhash_t *objthash = NULL, *funchash = NULL;
1117d62b00eSchristos   ctf_sect_t cts;
112*6881a400Schristos   ctf_dict_t *fp;
1137d62b00eSchristos 
1147d62b00eSchristos   libctf_init_debug();
1157d62b00eSchristos   dthash = ctf_dynhash_create (ctf_hash_integer, ctf_hash_eq_integer,
1167d62b00eSchristos 			       NULL, NULL);
1177d62b00eSchristos   if (dthash == NULL)
1187d62b00eSchristos     {
1197d62b00eSchristos       ctf_set_open_errno (errp, EAGAIN);
1207d62b00eSchristos       goto err;
1217d62b00eSchristos     }
1227d62b00eSchristos 
1237d62b00eSchristos   dvhash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
1247d62b00eSchristos 			       NULL, NULL);
1257d62b00eSchristos   if (dvhash == NULL)
1267d62b00eSchristos     {
1277d62b00eSchristos       ctf_set_open_errno (errp, EAGAIN);
1287d62b00eSchristos       goto err_dt;
1297d62b00eSchristos     }
1307d62b00eSchristos 
1317d62b00eSchristos   structs = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
1327d62b00eSchristos 				NULL, NULL);
1337d62b00eSchristos   unions = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
1347d62b00eSchristos 			       NULL, NULL);
1357d62b00eSchristos   enums = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
1367d62b00eSchristos 			      NULL, NULL);
1377d62b00eSchristos   names = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
1387d62b00eSchristos 			      NULL, NULL);
139*6881a400Schristos   objthash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
140*6881a400Schristos 				 free, NULL);
141*6881a400Schristos   funchash = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
142*6881a400Schristos 				 free, NULL);
1437d62b00eSchristos   if (!structs || !unions || !enums || !names)
1447d62b00eSchristos     {
1457d62b00eSchristos       ctf_set_open_errno (errp, EAGAIN);
1467d62b00eSchristos       goto err_dv;
1477d62b00eSchristos     }
1487d62b00eSchristos 
1497d62b00eSchristos   cts.cts_name = _CTF_SECTION;
1507d62b00eSchristos   cts.cts_data = &hdr;
1517d62b00eSchristos   cts.cts_size = sizeof (hdr);
1527d62b00eSchristos   cts.cts_entsize = 1;
1537d62b00eSchristos 
1547d62b00eSchristos   if ((fp = ctf_bufopen_internal (&cts, NULL, NULL, NULL, 1, errp)) == NULL)
1557d62b00eSchristos     goto err_dv;
1567d62b00eSchristos 
1577d62b00eSchristos   fp->ctf_structs.ctn_writable = structs;
1587d62b00eSchristos   fp->ctf_unions.ctn_writable = unions;
1597d62b00eSchristos   fp->ctf_enums.ctn_writable = enums;
1607d62b00eSchristos   fp->ctf_names.ctn_writable = names;
161*6881a400Schristos   fp->ctf_objthash = objthash;
162*6881a400Schristos   fp->ctf_funchash = funchash;
1637d62b00eSchristos   fp->ctf_dthash = dthash;
1647d62b00eSchristos   fp->ctf_dvhash = dvhash;
1657d62b00eSchristos   fp->ctf_dtoldid = 0;
1667d62b00eSchristos   fp->ctf_snapshots = 1;
1677d62b00eSchristos   fp->ctf_snapshot_lu = 0;
1687d62b00eSchristos   fp->ctf_flags |= LCTF_DIRTY;
1697d62b00eSchristos 
1707d62b00eSchristos   ctf_set_ctl_hashes (fp);
1717d62b00eSchristos   ctf_setmodel (fp, CTF_MODEL_NATIVE);
1727d62b00eSchristos   if (ctf_grow_ptrtab (fp) < 0)
1737d62b00eSchristos     {
1747d62b00eSchristos       ctf_set_open_errno (errp, ctf_errno (fp));
175*6881a400Schristos       ctf_dict_close (fp);
1767d62b00eSchristos       return NULL;
1777d62b00eSchristos     }
1787d62b00eSchristos 
1797d62b00eSchristos   return fp;
1807d62b00eSchristos 
1817d62b00eSchristos  err_dv:
1827d62b00eSchristos   ctf_dynhash_destroy (structs);
1837d62b00eSchristos   ctf_dynhash_destroy (unions);
1847d62b00eSchristos   ctf_dynhash_destroy (enums);
1857d62b00eSchristos   ctf_dynhash_destroy (names);
186*6881a400Schristos   ctf_dynhash_destroy (objthash);
187*6881a400Schristos   ctf_dynhash_destroy (funchash);
1887d62b00eSchristos   ctf_dynhash_destroy (dvhash);
1897d62b00eSchristos  err_dt:
1907d62b00eSchristos   ctf_dynhash_destroy (dthash);
1917d62b00eSchristos  err:
1927d62b00eSchristos   return NULL;
1937d62b00eSchristos }
1947d62b00eSchristos 
1957d62b00eSchristos /* Compatibility: just update the threshold for ctf_discard.  */
1967d62b00eSchristos int
197*6881a400Schristos ctf_update (ctf_dict_t *fp)
1987d62b00eSchristos {
1997d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
2007d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
2017d62b00eSchristos 
2027d62b00eSchristos   fp->ctf_dtoldid = fp->ctf_typemax;
2037d62b00eSchristos   return 0;
2047d62b00eSchristos }
2057d62b00eSchristos 
2067d62b00eSchristos ctf_names_t *
207*6881a400Schristos ctf_name_table (ctf_dict_t *fp, int kind)
2087d62b00eSchristos {
2097d62b00eSchristos   switch (kind)
2107d62b00eSchristos     {
2117d62b00eSchristos     case CTF_K_STRUCT:
2127d62b00eSchristos       return &fp->ctf_structs;
2137d62b00eSchristos     case CTF_K_UNION:
2147d62b00eSchristos       return &fp->ctf_unions;
2157d62b00eSchristos     case CTF_K_ENUM:
2167d62b00eSchristos       return &fp->ctf_enums;
2177d62b00eSchristos     default:
2187d62b00eSchristos       return &fp->ctf_names;
2197d62b00eSchristos     }
2207d62b00eSchristos }
2217d62b00eSchristos 
2227d62b00eSchristos int
223*6881a400Schristos ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
2247d62b00eSchristos {
2257d62b00eSchristos   const char *name;
2267d62b00eSchristos   if (ctf_dynhash_insert (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type,
2277d62b00eSchristos 			  dtd) < 0)
228*6881a400Schristos     {
229*6881a400Schristos       ctf_set_errno (fp, ENOMEM);
2307d62b00eSchristos       return -1;
231*6881a400Schristos     }
2327d62b00eSchristos 
2337d62b00eSchristos   if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name
2347d62b00eSchristos       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
2357d62b00eSchristos     {
2367d62b00eSchristos       if (ctf_dynhash_insert (ctf_name_table (fp, kind)->ctn_writable,
2377d62b00eSchristos 			      (char *) name, (void *) (uintptr_t)
2387d62b00eSchristos 			      dtd->dtd_type) < 0)
2397d62b00eSchristos 	{
2407d62b00eSchristos 	  ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
2417d62b00eSchristos 			      dtd->dtd_type);
242*6881a400Schristos 	  ctf_set_errno (fp, ENOMEM);
2437d62b00eSchristos 	  return -1;
2447d62b00eSchristos 	}
2457d62b00eSchristos     }
2467d62b00eSchristos   ctf_list_append (&fp->ctf_dtdefs, dtd);
2477d62b00eSchristos   return 0;
2487d62b00eSchristos }
2497d62b00eSchristos 
2507d62b00eSchristos void
251*6881a400Schristos ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
2527d62b00eSchristos {
2537d62b00eSchristos   int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
254*6881a400Schristos   size_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
2557d62b00eSchristos   int name_kind = kind;
2567d62b00eSchristos   const char *name;
2577d62b00eSchristos 
2587d62b00eSchristos   ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
2597d62b00eSchristos 
2607d62b00eSchristos   switch (kind)
2617d62b00eSchristos     {
2627d62b00eSchristos     case CTF_K_STRUCT:
2637d62b00eSchristos     case CTF_K_UNION:
2647d62b00eSchristos       {
265*6881a400Schristos 	ctf_lmember_t *memb = (ctf_lmember_t *) dtd->dtd_vlen;
266*6881a400Schristos 	size_t i;
267*6881a400Schristos 
268*6881a400Schristos 	for (i = 0; i < vlen; i++)
269*6881a400Schristos 	  ctf_str_remove_ref (fp, ctf_strraw (fp, memb[i].ctlm_name),
270*6881a400Schristos 			      &memb[i].ctlm_name);
2717d62b00eSchristos       }
2727d62b00eSchristos       break;
273*6881a400Schristos     case CTF_K_ENUM:
274*6881a400Schristos       {
275*6881a400Schristos 	ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
276*6881a400Schristos 	size_t i;
277*6881a400Schristos 
278*6881a400Schristos 	for (i = 0; i < vlen; i++)
279*6881a400Schristos 	  ctf_str_remove_ref (fp, ctf_strraw (fp, en[i].cte_name),
280*6881a400Schristos 			      &en[i].cte_name);
281*6881a400Schristos       }
2827d62b00eSchristos       break;
2837d62b00eSchristos     case CTF_K_FORWARD:
2847d62b00eSchristos       name_kind = dtd->dtd_data.ctt_type;
2857d62b00eSchristos       break;
2867d62b00eSchristos     }
287*6881a400Schristos   free (dtd->dtd_vlen);
288*6881a400Schristos   dtd->dtd_vlen_alloc = 0;
2897d62b00eSchristos 
2907d62b00eSchristos   if (dtd->dtd_data.ctt_name
2917d62b00eSchristos       && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL
2927d62b00eSchristos       && LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info))
2937d62b00eSchristos     {
2947d62b00eSchristos       ctf_dynhash_remove (ctf_name_table (fp, name_kind)->ctn_writable,
2957d62b00eSchristos 			  name);
2967d62b00eSchristos       ctf_str_remove_ref (fp, name, &dtd->dtd_data.ctt_name);
2977d62b00eSchristos     }
2987d62b00eSchristos 
2997d62b00eSchristos   ctf_list_delete (&fp->ctf_dtdefs, dtd);
3007d62b00eSchristos   free (dtd);
3017d62b00eSchristos }
3027d62b00eSchristos 
3037d62b00eSchristos ctf_dtdef_t *
304*6881a400Schristos ctf_dtd_lookup (const ctf_dict_t *fp, ctf_id_t type)
3057d62b00eSchristos {
3067d62b00eSchristos   return (ctf_dtdef_t *)
3077d62b00eSchristos     ctf_dynhash_lookup (fp->ctf_dthash, (void *) (uintptr_t) type);
3087d62b00eSchristos }
3097d62b00eSchristos 
3107d62b00eSchristos ctf_dtdef_t *
311*6881a400Schristos ctf_dynamic_type (const ctf_dict_t *fp, ctf_id_t id)
3127d62b00eSchristos {
3137d62b00eSchristos   ctf_id_t idx;
3147d62b00eSchristos 
3157d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
3167d62b00eSchristos     return NULL;
3177d62b00eSchristos 
3187d62b00eSchristos   if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, id))
3197d62b00eSchristos     fp = fp->ctf_parent;
3207d62b00eSchristos 
3217d62b00eSchristos   idx = LCTF_TYPE_TO_INDEX(fp, id);
3227d62b00eSchristos 
3237d62b00eSchristos   if ((unsigned long) idx <= fp->ctf_typemax)
3247d62b00eSchristos     return ctf_dtd_lookup (fp, id);
3257d62b00eSchristos   return NULL;
3267d62b00eSchristos }
3277d62b00eSchristos 
3287d62b00eSchristos int
329*6881a400Schristos ctf_dvd_insert (ctf_dict_t *fp, ctf_dvdef_t *dvd)
3307d62b00eSchristos {
3317d62b00eSchristos   if (ctf_dynhash_insert (fp->ctf_dvhash, dvd->dvd_name, dvd) < 0)
332*6881a400Schristos     {
333*6881a400Schristos       ctf_set_errno (fp, ENOMEM);
3347d62b00eSchristos       return -1;
335*6881a400Schristos     }
3367d62b00eSchristos   ctf_list_append (&fp->ctf_dvdefs, dvd);
3377d62b00eSchristos   return 0;
3387d62b00eSchristos }
3397d62b00eSchristos 
3407d62b00eSchristos void
341*6881a400Schristos ctf_dvd_delete (ctf_dict_t *fp, ctf_dvdef_t *dvd)
3427d62b00eSchristos {
3437d62b00eSchristos   ctf_dynhash_remove (fp->ctf_dvhash, dvd->dvd_name);
3447d62b00eSchristos   free (dvd->dvd_name);
3457d62b00eSchristos 
3467d62b00eSchristos   ctf_list_delete (&fp->ctf_dvdefs, dvd);
3477d62b00eSchristos   free (dvd);
3487d62b00eSchristos }
3497d62b00eSchristos 
3507d62b00eSchristos ctf_dvdef_t *
351*6881a400Schristos ctf_dvd_lookup (const ctf_dict_t *fp, const char *name)
3527d62b00eSchristos {
3537d62b00eSchristos   return (ctf_dvdef_t *) ctf_dynhash_lookup (fp->ctf_dvhash, name);
3547d62b00eSchristos }
3557d62b00eSchristos 
3567d62b00eSchristos /* Discard all of the dynamic type definitions and variable definitions that
357*6881a400Schristos    have been added to the dict since the last call to ctf_update().  We locate
358*6881a400Schristos    such types by scanning the dtd list and deleting elements that have type IDs
359*6881a400Schristos    greater than ctf_dtoldid, which is set by ctf_update(), above, and by
360*6881a400Schristos    scanning the variable list and deleting elements that have update IDs equal
361*6881a400Schristos    to the current value of the last-update snapshot count (indicating that they
362*6881a400Schristos    were added after the most recent call to ctf_update()).  */
3637d62b00eSchristos int
364*6881a400Schristos ctf_discard (ctf_dict_t *fp)
3657d62b00eSchristos {
3667d62b00eSchristos   ctf_snapshot_id_t last_update =
3677d62b00eSchristos     { fp->ctf_dtoldid,
3687d62b00eSchristos       fp->ctf_snapshot_lu + 1 };
3697d62b00eSchristos 
3707d62b00eSchristos   /* Update required?  */
3717d62b00eSchristos   if (!(fp->ctf_flags & LCTF_DIRTY))
3727d62b00eSchristos     return 0;
3737d62b00eSchristos 
3747d62b00eSchristos   return (ctf_rollback (fp, last_update));
3757d62b00eSchristos }
3767d62b00eSchristos 
3777d62b00eSchristos ctf_snapshot_id_t
378*6881a400Schristos ctf_snapshot (ctf_dict_t *fp)
3797d62b00eSchristos {
3807d62b00eSchristos   ctf_snapshot_id_t snapid;
3817d62b00eSchristos   snapid.dtd_id = fp->ctf_typemax;
3827d62b00eSchristos   snapid.snapshot_id = fp->ctf_snapshots++;
3837d62b00eSchristos   return snapid;
3847d62b00eSchristos }
3857d62b00eSchristos 
3867d62b00eSchristos /* Like ctf_discard(), only discards everything after a particular ID.  */
3877d62b00eSchristos int
388*6881a400Schristos ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
3897d62b00eSchristos {
3907d62b00eSchristos   ctf_dtdef_t *dtd, *ntd;
3917d62b00eSchristos   ctf_dvdef_t *dvd, *nvd;
3927d62b00eSchristos 
3937d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
3947d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
3957d62b00eSchristos 
3967d62b00eSchristos   if (fp->ctf_snapshot_lu >= id.snapshot_id)
3977d62b00eSchristos     return (ctf_set_errno (fp, ECTF_OVERROLLBACK));
3987d62b00eSchristos 
3997d62b00eSchristos   for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
4007d62b00eSchristos     {
4017d62b00eSchristos       int kind;
4027d62b00eSchristos       const char *name;
4037d62b00eSchristos 
4047d62b00eSchristos       ntd = ctf_list_next (dtd);
4057d62b00eSchristos 
4067d62b00eSchristos       if (LCTF_TYPE_TO_INDEX (fp, dtd->dtd_type) <= id.dtd_id)
4077d62b00eSchristos 	continue;
4087d62b00eSchristos 
4097d62b00eSchristos       kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
4107d62b00eSchristos       if (kind == CTF_K_FORWARD)
4117d62b00eSchristos 	kind = dtd->dtd_data.ctt_type;
4127d62b00eSchristos 
4137d62b00eSchristos       if (dtd->dtd_data.ctt_name
4147d62b00eSchristos 	  && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL
4157d62b00eSchristos 	  && LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info))
4167d62b00eSchristos 	{
4177d62b00eSchristos 	  ctf_dynhash_remove (ctf_name_table (fp, kind)->ctn_writable,
4187d62b00eSchristos 			      name);
4197d62b00eSchristos 	  ctf_str_remove_ref (fp, name, &dtd->dtd_data.ctt_name);
4207d62b00eSchristos 	}
4217d62b00eSchristos 
4227d62b00eSchristos       ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
4237d62b00eSchristos       ctf_dtd_delete (fp, dtd);
4247d62b00eSchristos     }
4257d62b00eSchristos 
4267d62b00eSchristos   for (dvd = ctf_list_next (&fp->ctf_dvdefs); dvd != NULL; dvd = nvd)
4277d62b00eSchristos     {
4287d62b00eSchristos       nvd = ctf_list_next (dvd);
4297d62b00eSchristos 
4307d62b00eSchristos       if (dvd->dvd_snapshots <= id.snapshot_id)
4317d62b00eSchristos 	continue;
4327d62b00eSchristos 
4337d62b00eSchristos       ctf_dvd_delete (fp, dvd);
4347d62b00eSchristos     }
4357d62b00eSchristos 
4367d62b00eSchristos   fp->ctf_typemax = id.dtd_id;
4377d62b00eSchristos   fp->ctf_snapshots = id.snapshot_id;
4387d62b00eSchristos 
4397d62b00eSchristos   if (fp->ctf_snapshots == fp->ctf_snapshot_lu)
4407d62b00eSchristos     fp->ctf_flags &= ~LCTF_DIRTY;
4417d62b00eSchristos 
4427d62b00eSchristos   return 0;
4437d62b00eSchristos }
4447d62b00eSchristos 
445*6881a400Schristos /* Note: vlen is the amount of space *allocated* for the vlen.  It may well not
446*6881a400Schristos    be the amount of space used (yet): the space used is declared in per-kind
447*6881a400Schristos    fashion in the dtd_data's info word.  */
4487d62b00eSchristos static ctf_id_t
449*6881a400Schristos ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
450*6881a400Schristos 		 size_t vlen, ctf_dtdef_t **rp)
4517d62b00eSchristos {
4527d62b00eSchristos   ctf_dtdef_t *dtd;
4537d62b00eSchristos   ctf_id_t type;
4547d62b00eSchristos 
4557d62b00eSchristos   if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
4567d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
4577d62b00eSchristos 
4587d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
4597d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
4607d62b00eSchristos 
4617d62b00eSchristos   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) >= CTF_MAX_TYPE)
4627d62b00eSchristos     return (ctf_set_errno (fp, ECTF_FULL));
4637d62b00eSchristos 
4647d62b00eSchristos   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
4657d62b00eSchristos     return (ctf_set_errno (fp, ECTF_FULL));
4667d62b00eSchristos 
4677d62b00eSchristos   /* Make sure ptrtab always grows to be big enough for all types.  */
4687d62b00eSchristos   if (ctf_grow_ptrtab (fp) < 0)
4697d62b00eSchristos       return CTF_ERR;				/* errno is set for us. */
4707d62b00eSchristos 
471*6881a400Schristos   if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
4727d62b00eSchristos     return (ctf_set_errno (fp, EAGAIN));
4737d62b00eSchristos 
474*6881a400Schristos   dtd->dtd_vlen_alloc = vlen;
475*6881a400Schristos   if (vlen > 0)
476*6881a400Schristos     {
477*6881a400Schristos       if ((dtd->dtd_vlen = calloc (1, vlen)) == NULL)
478*6881a400Schristos 	goto oom;
479*6881a400Schristos     }
480*6881a400Schristos   else
481*6881a400Schristos     dtd->dtd_vlen = NULL;
482*6881a400Schristos 
4837d62b00eSchristos   type = ++fp->ctf_typemax;
4847d62b00eSchristos   type = LCTF_INDEX_TO_TYPE (fp, type, (fp->ctf_flags & LCTF_CHILD));
4857d62b00eSchristos 
486*6881a400Schristos   dtd->dtd_data.ctt_name = ctf_str_add_pending (fp, name,
487*6881a400Schristos 						&dtd->dtd_data.ctt_name);
4887d62b00eSchristos   dtd->dtd_type = type;
4897d62b00eSchristos 
4907d62b00eSchristos   if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0')
491*6881a400Schristos     goto oom;
4927d62b00eSchristos 
4937d62b00eSchristos   if (ctf_dtd_insert (fp, dtd, flag, kind) < 0)
494*6881a400Schristos     goto err;					/* errno is set for us.  */
495*6881a400Schristos 
4967d62b00eSchristos   fp->ctf_flags |= LCTF_DIRTY;
4977d62b00eSchristos 
4987d62b00eSchristos   *rp = dtd;
4997d62b00eSchristos   return type;
500*6881a400Schristos 
501*6881a400Schristos  oom:
502*6881a400Schristos   ctf_set_errno (fp, EAGAIN);
503*6881a400Schristos  err:
504*6881a400Schristos   free (dtd->dtd_vlen);
505*6881a400Schristos   free (dtd);
506*6881a400Schristos   return CTF_ERR;
5077d62b00eSchristos }
5087d62b00eSchristos 
5097d62b00eSchristos /* When encoding integer sizes, we want to convert a byte count in the range
5107d62b00eSchristos    1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc).  The clp2() function
5117d62b00eSchristos    is a clever implementation from "Hacker's Delight" by Henry Warren, Jr.  */
5127d62b00eSchristos static size_t
5137d62b00eSchristos clp2 (size_t x)
5147d62b00eSchristos {
5157d62b00eSchristos   x--;
5167d62b00eSchristos 
5177d62b00eSchristos   x |= (x >> 1);
5187d62b00eSchristos   x |= (x >> 2);
5197d62b00eSchristos   x |= (x >> 4);
5207d62b00eSchristos   x |= (x >> 8);
5217d62b00eSchristos   x |= (x >> 16);
5227d62b00eSchristos 
5237d62b00eSchristos   return (x + 1);
5247d62b00eSchristos }
5257d62b00eSchristos 
5267d62b00eSchristos ctf_id_t
527*6881a400Schristos ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
5287d62b00eSchristos 		 const char *name, const ctf_encoding_t *ep, uint32_t kind)
5297d62b00eSchristos {
5307d62b00eSchristos   ctf_dtdef_t *dtd;
5317d62b00eSchristos   ctf_id_t type;
532*6881a400Schristos   uint32_t encoding;
5337d62b00eSchristos 
5347d62b00eSchristos   if (ep == NULL)
5357d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
5367d62b00eSchristos 
537*6881a400Schristos   if (name == NULL || name[0] == '\0')
538*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NONAME));
539*6881a400Schristos 
540*6881a400Schristos   if (!ctf_assert (fp, kind == CTF_K_INTEGER || kind == CTF_K_FLOAT))
541*6881a400Schristos     return -1;					/* errno is set for us.  */
542*6881a400Schristos 
543*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, name, kind, sizeof (uint32_t),
544*6881a400Schristos 			       &dtd)) == CTF_ERR)
5457d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
5467d62b00eSchristos 
5477d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0);
5487d62b00eSchristos   dtd->dtd_data.ctt_size = clp2 (P2ROUNDUP (ep->cte_bits, CHAR_BIT)
5497d62b00eSchristos 				 / CHAR_BIT);
550*6881a400Schristos   switch (kind)
551*6881a400Schristos     {
552*6881a400Schristos     case CTF_K_INTEGER:
553*6881a400Schristos       encoding = CTF_INT_DATA (ep->cte_format, ep->cte_offset, ep->cte_bits);
554*6881a400Schristos       break;
555*6881a400Schristos     case CTF_K_FLOAT:
556*6881a400Schristos       encoding = CTF_FP_DATA (ep->cte_format, ep->cte_offset, ep->cte_bits);
557*6881a400Schristos       break;
558*6881a400Schristos     }
559*6881a400Schristos   memcpy (dtd->dtd_vlen, &encoding, sizeof (encoding));
5607d62b00eSchristos 
5617d62b00eSchristos   return type;
5627d62b00eSchristos }
5637d62b00eSchristos 
5647d62b00eSchristos ctf_id_t
565*6881a400Schristos ctf_add_reftype (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref, uint32_t kind)
5667d62b00eSchristos {
5677d62b00eSchristos   ctf_dtdef_t *dtd;
5687d62b00eSchristos   ctf_id_t type;
569*6881a400Schristos   ctf_dict_t *tmp = fp;
5707d62b00eSchristos   int child = fp->ctf_flags & LCTF_CHILD;
5717d62b00eSchristos 
5727d62b00eSchristos   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
5737d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
5747d62b00eSchristos 
5757d62b00eSchristos   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
5767d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
5777d62b00eSchristos 
578*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, NULL, kind, 0, &dtd)) == CTF_ERR)
5797d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
5807d62b00eSchristos 
5817d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, 0);
5827d62b00eSchristos   dtd->dtd_data.ctt_type = (uint32_t) ref;
5837d62b00eSchristos 
5847d62b00eSchristos   if (kind != CTF_K_POINTER)
5857d62b00eSchristos     return type;
5867d62b00eSchristos 
587*6881a400Schristos   /* If we are adding a pointer, update the ptrtab, pointing at this type from
588*6881a400Schristos      the type it points to.  Note that ctf_typemax is at this point one higher
589*6881a400Schristos      than we want to check against, because it's just been incremented for the
590*6881a400Schristos      addition of this type.  The pptrtab is lazily-updated as needed, so is not
591*6881a400Schristos      touched here.  */
5927d62b00eSchristos 
5937d62b00eSchristos   uint32_t type_idx = LCTF_TYPE_TO_INDEX (fp, type);
5947d62b00eSchristos   uint32_t ref_idx = LCTF_TYPE_TO_INDEX (fp, ref);
5957d62b00eSchristos 
5967d62b00eSchristos   if (LCTF_TYPE_ISCHILD (fp, ref) == child
5977d62b00eSchristos       && ref_idx < fp->ctf_typemax)
5987d62b00eSchristos     fp->ctf_ptrtab[ref_idx] = type_idx;
5997d62b00eSchristos 
6007d62b00eSchristos   return type;
6017d62b00eSchristos }
6027d62b00eSchristos 
6037d62b00eSchristos ctf_id_t
604*6881a400Schristos ctf_add_slice (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref,
6057d62b00eSchristos 	       const ctf_encoding_t *ep)
6067d62b00eSchristos {
6077d62b00eSchristos   ctf_dtdef_t *dtd;
608*6881a400Schristos   ctf_slice_t slice;
6097d62b00eSchristos   ctf_id_t resolved_ref = ref;
6107d62b00eSchristos   ctf_id_t type;
6117d62b00eSchristos   int kind;
6127d62b00eSchristos   const ctf_type_t *tp;
613*6881a400Schristos   ctf_dict_t *tmp = fp;
6147d62b00eSchristos 
6157d62b00eSchristos   if (ep == NULL)
6167d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
6177d62b00eSchristos 
6187d62b00eSchristos   if ((ep->cte_bits > 255) || (ep->cte_offset > 255))
6197d62b00eSchristos     return (ctf_set_errno (fp, ECTF_SLICEOVERFLOW));
6207d62b00eSchristos 
6217d62b00eSchristos   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
6227d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
6237d62b00eSchristos 
6247d62b00eSchristos   if (ref != 0 && ((tp = ctf_lookup_by_id (&tmp, ref)) == NULL))
6257d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
6267d62b00eSchristos 
6277d62b00eSchristos   /* Make sure we ultimately point to an integral type.  We also allow slices to
6287d62b00eSchristos      point to the unimplemented type, for now, because the compiler can emit
6297d62b00eSchristos      such slices, though they're not very much use.  */
6307d62b00eSchristos 
6317d62b00eSchristos   resolved_ref = ctf_type_resolve_unsliced (tmp, ref);
6327d62b00eSchristos   kind = ctf_type_kind_unsliced (tmp, resolved_ref);
6337d62b00eSchristos 
6347d62b00eSchristos   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) &&
6357d62b00eSchristos       (kind != CTF_K_ENUM)
6367d62b00eSchristos       && (ref != 0))
6377d62b00eSchristos     return (ctf_set_errno (fp, ECTF_NOTINTFP));
6387d62b00eSchristos 
639*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_SLICE,
640*6881a400Schristos 			       sizeof (ctf_slice_t), &dtd)) == CTF_ERR)
6417d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
6427d62b00eSchristos 
643*6881a400Schristos   memset (&slice, 0, sizeof (ctf_slice_t));
644*6881a400Schristos 
6457d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_SLICE, flag, 0);
6467d62b00eSchristos   dtd->dtd_data.ctt_size = clp2 (P2ROUNDUP (ep->cte_bits, CHAR_BIT)
6477d62b00eSchristos 				 / CHAR_BIT);
648*6881a400Schristos   slice.cts_type = (uint32_t) ref;
649*6881a400Schristos   slice.cts_bits = ep->cte_bits;
650*6881a400Schristos   slice.cts_offset = ep->cte_offset;
651*6881a400Schristos   memcpy (dtd->dtd_vlen, &slice, sizeof (ctf_slice_t));
6527d62b00eSchristos 
6537d62b00eSchristos   return type;
6547d62b00eSchristos }
6557d62b00eSchristos 
6567d62b00eSchristos ctf_id_t
657*6881a400Schristos ctf_add_integer (ctf_dict_t *fp, uint32_t flag,
6587d62b00eSchristos 		 const char *name, const ctf_encoding_t *ep)
6597d62b00eSchristos {
6607d62b00eSchristos   return (ctf_add_encoded (fp, flag, name, ep, CTF_K_INTEGER));
6617d62b00eSchristos }
6627d62b00eSchristos 
6637d62b00eSchristos ctf_id_t
664*6881a400Schristos ctf_add_float (ctf_dict_t *fp, uint32_t flag,
6657d62b00eSchristos 	       const char *name, const ctf_encoding_t *ep)
6667d62b00eSchristos {
6677d62b00eSchristos   return (ctf_add_encoded (fp, flag, name, ep, CTF_K_FLOAT));
6687d62b00eSchristos }
6697d62b00eSchristos 
6707d62b00eSchristos ctf_id_t
671*6881a400Schristos ctf_add_pointer (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref)
6727d62b00eSchristos {
6737d62b00eSchristos   return (ctf_add_reftype (fp, flag, ref, CTF_K_POINTER));
6747d62b00eSchristos }
6757d62b00eSchristos 
6767d62b00eSchristos ctf_id_t
677*6881a400Schristos ctf_add_array (ctf_dict_t *fp, uint32_t flag, const ctf_arinfo_t *arp)
6787d62b00eSchristos {
6797d62b00eSchristos   ctf_dtdef_t *dtd;
680*6881a400Schristos   ctf_array_t cta;
6817d62b00eSchristos   ctf_id_t type;
682*6881a400Schristos   ctf_dict_t *tmp = fp;
6837d62b00eSchristos 
6847d62b00eSchristos   if (arp == NULL)
6857d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
6867d62b00eSchristos 
6877d62b00eSchristos   if (arp->ctr_contents != 0
6887d62b00eSchristos       && ctf_lookup_by_id (&tmp, arp->ctr_contents) == NULL)
6897d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
6907d62b00eSchristos 
6917d62b00eSchristos   tmp = fp;
6927d62b00eSchristos   if (ctf_lookup_by_id (&tmp, arp->ctr_index) == NULL)
6937d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
6947d62b00eSchristos 
695*6881a400Schristos   if (ctf_type_kind (fp, arp->ctr_index) == CTF_K_FORWARD)
696*6881a400Schristos     {
697*6881a400Schristos       ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
698*6881a400Schristos 		    _("ctf_add_array: index type %lx is incomplete"),
699*6881a400Schristos 		    arp->ctr_contents);
700*6881a400Schristos       return (ctf_set_errno (fp, ECTF_INCOMPLETE));
701*6881a400Schristos     }
702*6881a400Schristos 
703*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_ARRAY,
704*6881a400Schristos 			       sizeof (ctf_array_t), &dtd)) == CTF_ERR)
7057d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
7067d62b00eSchristos 
707*6881a400Schristos   memset (&cta, 0, sizeof (ctf_array_t));
708*6881a400Schristos 
7097d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ARRAY, flag, 0);
7107d62b00eSchristos   dtd->dtd_data.ctt_size = 0;
711*6881a400Schristos   cta.cta_contents = (uint32_t) arp->ctr_contents;
712*6881a400Schristos   cta.cta_index = (uint32_t) arp->ctr_index;
713*6881a400Schristos   cta.cta_nelems = arp->ctr_nelems;
714*6881a400Schristos   memcpy (dtd->dtd_vlen, &cta, sizeof (ctf_array_t));
7157d62b00eSchristos 
7167d62b00eSchristos   return type;
7177d62b00eSchristos }
7187d62b00eSchristos 
7197d62b00eSchristos int
720*6881a400Schristos ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
7217d62b00eSchristos {
7227d62b00eSchristos   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
723*6881a400Schristos   ctf_array_t *vlen;
7247d62b00eSchristos 
7257d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
7267d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
7277d62b00eSchristos 
7287d62b00eSchristos   if (dtd == NULL
7297d62b00eSchristos       || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
7307d62b00eSchristos     return (ctf_set_errno (fp, ECTF_BADID));
7317d62b00eSchristos 
732*6881a400Schristos   vlen = (ctf_array_t *) dtd->dtd_vlen;
7337d62b00eSchristos   fp->ctf_flags |= LCTF_DIRTY;
734*6881a400Schristos   vlen->cta_contents = (uint32_t) arp->ctr_contents;
735*6881a400Schristos   vlen->cta_index = (uint32_t) arp->ctr_index;
736*6881a400Schristos   vlen->cta_nelems = arp->ctr_nelems;
7377d62b00eSchristos 
7387d62b00eSchristos   return 0;
7397d62b00eSchristos }
7407d62b00eSchristos 
7417d62b00eSchristos ctf_id_t
742*6881a400Schristos ctf_add_function (ctf_dict_t *fp, uint32_t flag,
7437d62b00eSchristos 		  const ctf_funcinfo_t *ctc, const ctf_id_t *argv)
7447d62b00eSchristos {
7457d62b00eSchristos   ctf_dtdef_t *dtd;
7467d62b00eSchristos   ctf_id_t type;
7477d62b00eSchristos   uint32_t vlen;
748*6881a400Schristos   uint32_t *vdat;
749*6881a400Schristos   ctf_dict_t *tmp = fp;
750*6881a400Schristos   size_t initial_vlen;
7517d62b00eSchristos   size_t i;
7527d62b00eSchristos 
753*6881a400Schristos   if (!(fp->ctf_flags & LCTF_RDWR))
754*6881a400Schristos     return (ctf_set_errno (fp, ECTF_RDONLY));
755*6881a400Schristos 
7567d62b00eSchristos   if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0
7577d62b00eSchristos       || (ctc->ctc_argc != 0 && argv == NULL))
7587d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
7597d62b00eSchristos 
7607d62b00eSchristos   vlen = ctc->ctc_argc;
7617d62b00eSchristos   if (ctc->ctc_flags & CTF_FUNC_VARARG)
7627d62b00eSchristos     vlen++;	       /* Add trailing zero to indicate varargs (see below).  */
7637d62b00eSchristos 
7647d62b00eSchristos   if (ctc->ctc_return != 0
7657d62b00eSchristos       && ctf_lookup_by_id (&tmp, ctc->ctc_return) == NULL)
7667d62b00eSchristos     return CTF_ERR;				/* errno is set for us.  */
7677d62b00eSchristos 
7687d62b00eSchristos   if (vlen > CTF_MAX_VLEN)
7697d62b00eSchristos     return (ctf_set_errno (fp, EOVERFLOW));
7707d62b00eSchristos 
771*6881a400Schristos   /* One word extra allocated for padding for 4-byte alignment if need be.
772*6881a400Schristos      Not reflected in vlen: we don't want to copy anything into it, and
773*6881a400Schristos      it's in addition to (e.g.) the trailing 0 indicating varargs.  */
774*6881a400Schristos 
775*6881a400Schristos   initial_vlen = (sizeof (uint32_t) * (vlen + (vlen & 1)));
776*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, NULL, CTF_K_FUNCTION,
777*6881a400Schristos 			       initial_vlen, &dtd)) == CTF_ERR)
778*6881a400Schristos     return CTF_ERR;				/* errno is set for us.  */
779*6881a400Schristos 
780*6881a400Schristos   vdat = (uint32_t *) dtd->dtd_vlen;
7817d62b00eSchristos 
7827d62b00eSchristos   for (i = 0; i < ctc->ctc_argc; i++)
7837d62b00eSchristos     {
7847d62b00eSchristos       tmp = fp;
7857d62b00eSchristos       if (argv[i] != 0 && ctf_lookup_by_id (&tmp, argv[i]) == NULL)
7867d62b00eSchristos 	return CTF_ERR;				/* errno is set for us.  */
7877d62b00eSchristos       vdat[i] = (uint32_t) argv[i];
7887d62b00eSchristos     }
7897d62b00eSchristos 
7907d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FUNCTION, flag, vlen);
7917d62b00eSchristos   dtd->dtd_data.ctt_type = (uint32_t) ctc->ctc_return;
7927d62b00eSchristos 
7937d62b00eSchristos   if (ctc->ctc_flags & CTF_FUNC_VARARG)
7947d62b00eSchristos     vdat[vlen - 1] = 0;		   /* Add trailing zero to indicate varargs.  */
7957d62b00eSchristos 
7967d62b00eSchristos   return type;
7977d62b00eSchristos }
7987d62b00eSchristos 
7997d62b00eSchristos ctf_id_t
800*6881a400Schristos ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
8017d62b00eSchristos 		      size_t size)
8027d62b00eSchristos {
8037d62b00eSchristos   ctf_dtdef_t *dtd;
8047d62b00eSchristos   ctf_id_t type = 0;
805*6881a400Schristos   size_t initial_vlen = sizeof (ctf_lmember_t) * INITIAL_VLEN;
8067d62b00eSchristos 
8077d62b00eSchristos   /* Promote root-visible forwards to structs.  */
8087d62b00eSchristos   if (name != NULL)
8097d62b00eSchristos     type = ctf_lookup_by_rawname (fp, CTF_K_STRUCT, name);
8107d62b00eSchristos 
8117d62b00eSchristos   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
8127d62b00eSchristos     dtd = ctf_dtd_lookup (fp, type);
8137d62b00eSchristos   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_STRUCT,
814*6881a400Schristos 				    initial_vlen, &dtd)) == CTF_ERR)
8157d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
8167d62b00eSchristos 
817*6881a400Schristos   /* Forwards won't have any vlen yet.  */
818*6881a400Schristos   if (dtd->dtd_vlen_alloc == 0)
8197d62b00eSchristos     {
820*6881a400Schristos       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
821*6881a400Schristos 	return (ctf_set_errno (fp, ENOMEM));
822*6881a400Schristos       dtd->dtd_vlen_alloc = initial_vlen;
823*6881a400Schristos     }
824*6881a400Schristos 
825*6881a400Schristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0);
8267d62b00eSchristos   dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
8277d62b00eSchristos   dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
8287d62b00eSchristos   dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
8297d62b00eSchristos 
8307d62b00eSchristos   return type;
8317d62b00eSchristos }
8327d62b00eSchristos 
8337d62b00eSchristos ctf_id_t
834*6881a400Schristos ctf_add_struct (ctf_dict_t *fp, uint32_t flag, const char *name)
8357d62b00eSchristos {
8367d62b00eSchristos   return (ctf_add_struct_sized (fp, flag, name, 0));
8377d62b00eSchristos }
8387d62b00eSchristos 
8397d62b00eSchristos ctf_id_t
840*6881a400Schristos ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
8417d62b00eSchristos 		     size_t size)
8427d62b00eSchristos {
8437d62b00eSchristos   ctf_dtdef_t *dtd;
8447d62b00eSchristos   ctf_id_t type = 0;
845*6881a400Schristos   size_t initial_vlen = sizeof (ctf_lmember_t) * INITIAL_VLEN;
8467d62b00eSchristos 
8477d62b00eSchristos   /* Promote root-visible forwards to unions.  */
8487d62b00eSchristos   if (name != NULL)
8497d62b00eSchristos     type = ctf_lookup_by_rawname (fp, CTF_K_UNION, name);
8507d62b00eSchristos 
8517d62b00eSchristos   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
8527d62b00eSchristos     dtd = ctf_dtd_lookup (fp, type);
8537d62b00eSchristos   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_UNION,
854*6881a400Schristos 				    initial_vlen, &dtd)) == CTF_ERR)
8557d62b00eSchristos     return CTF_ERR;		/* errno is set for us */
8567d62b00eSchristos 
857*6881a400Schristos   /* Forwards won't have any vlen yet.  */
858*6881a400Schristos   if (dtd->dtd_vlen_alloc == 0)
8597d62b00eSchristos     {
860*6881a400Schristos       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
861*6881a400Schristos 	return (ctf_set_errno (fp, ENOMEM));
862*6881a400Schristos       dtd->dtd_vlen_alloc = initial_vlen;
863*6881a400Schristos     }
864*6881a400Schristos 
865*6881a400Schristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0);
8667d62b00eSchristos   dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
8677d62b00eSchristos   dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
8687d62b00eSchristos   dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
8697d62b00eSchristos 
8707d62b00eSchristos   return type;
8717d62b00eSchristos }
8727d62b00eSchristos 
8737d62b00eSchristos ctf_id_t
874*6881a400Schristos ctf_add_union (ctf_dict_t *fp, uint32_t flag, const char *name)
8757d62b00eSchristos {
8767d62b00eSchristos   return (ctf_add_union_sized (fp, flag, name, 0));
8777d62b00eSchristos }
8787d62b00eSchristos 
8797d62b00eSchristos ctf_id_t
880*6881a400Schristos ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
8817d62b00eSchristos {
8827d62b00eSchristos   ctf_dtdef_t *dtd;
8837d62b00eSchristos   ctf_id_t type = 0;
884*6881a400Schristos   size_t initial_vlen = sizeof (ctf_enum_t) * INITIAL_VLEN;
8857d62b00eSchristos 
8867d62b00eSchristos   /* Promote root-visible forwards to enums.  */
8877d62b00eSchristos   if (name != NULL)
8887d62b00eSchristos     type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name);
8897d62b00eSchristos 
8907d62b00eSchristos   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
8917d62b00eSchristos     dtd = ctf_dtd_lookup (fp, type);
8927d62b00eSchristos   else if ((type = ctf_add_generic (fp, flag, name, CTF_K_ENUM,
893*6881a400Schristos 				    initial_vlen, &dtd)) == CTF_ERR)
8947d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
8957d62b00eSchristos 
896*6881a400Schristos   /* Forwards won't have any vlen yet.  */
897*6881a400Schristos   if (dtd->dtd_vlen_alloc == 0)
898*6881a400Schristos     {
899*6881a400Schristos       if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL)
900*6881a400Schristos 	return (ctf_set_errno (fp, ENOMEM));
901*6881a400Schristos       dtd->dtd_vlen_alloc = initial_vlen;
902*6881a400Schristos     }
903*6881a400Schristos 
9047d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
9057d62b00eSchristos   dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
9067d62b00eSchristos 
9077d62b00eSchristos   return type;
9087d62b00eSchristos }
9097d62b00eSchristos 
9107d62b00eSchristos ctf_id_t
911*6881a400Schristos ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
9127d62b00eSchristos 		      const ctf_encoding_t *ep)
9137d62b00eSchristos {
9147d62b00eSchristos   ctf_id_t type = 0;
9157d62b00eSchristos 
9167d62b00eSchristos   /* First, create the enum if need be, using most of the same machinery as
9177d62b00eSchristos      ctf_add_enum(), to ensure that we do not allow things past that are not
9187d62b00eSchristos      enums or forwards to them.  (This includes other slices: you cannot slice a
9197d62b00eSchristos      slice, which would be a useless thing to do anyway.)  */
9207d62b00eSchristos 
9217d62b00eSchristos   if (name != NULL)
9227d62b00eSchristos     type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name);
9237d62b00eSchristos 
9247d62b00eSchristos   if (type != 0)
9257d62b00eSchristos     {
9267d62b00eSchristos       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
9277d62b00eSchristos 	  (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
9287d62b00eSchristos 	return (ctf_set_errno (fp, ECTF_NOTINTFP));
9297d62b00eSchristos     }
9307d62b00eSchristos   else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
9317d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
9327d62b00eSchristos 
9337d62b00eSchristos   /* Now attach a suitable slice to it.  */
9347d62b00eSchristos 
9357d62b00eSchristos   return ctf_add_slice (fp, flag, type, ep);
9367d62b00eSchristos }
9377d62b00eSchristos 
9387d62b00eSchristos ctf_id_t
939*6881a400Schristos ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
9407d62b00eSchristos 		 uint32_t kind)
9417d62b00eSchristos {
9427d62b00eSchristos   ctf_dtdef_t *dtd;
9437d62b00eSchristos   ctf_id_t type = 0;
9447d62b00eSchristos 
9457d62b00eSchristos   if (!ctf_forwardable_kind (kind))
9467d62b00eSchristos     return (ctf_set_errno (fp, ECTF_NOTSUE));
9477d62b00eSchristos 
948*6881a400Schristos   if (name == NULL || name[0] == '\0')
949*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NONAME));
950*6881a400Schristos 
9517d62b00eSchristos   /* If the type is already defined or exists as a forward tag, just
9527d62b00eSchristos      return the ctf_id_t of the existing definition.  */
9537d62b00eSchristos 
9547d62b00eSchristos   type = ctf_lookup_by_rawname (fp, kind, name);
9557d62b00eSchristos 
9567d62b00eSchristos   if (type)
9577d62b00eSchristos     return type;
9587d62b00eSchristos 
959*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, name, kind, 0, &dtd)) == CTF_ERR)
9607d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
9617d62b00eSchristos 
9627d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
9637d62b00eSchristos   dtd->dtd_data.ctt_type = kind;
9647d62b00eSchristos 
9657d62b00eSchristos   return type;
9667d62b00eSchristos }
9677d62b00eSchristos 
9687d62b00eSchristos ctf_id_t
969*6881a400Schristos ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
970*6881a400Schristos {
971*6881a400Schristos   ctf_dtdef_t *dtd;
972*6881a400Schristos   ctf_id_t type = 0;
973*6881a400Schristos 
974*6881a400Schristos   /* If a type is already defined with this name, error (if not CTF_K_UNKNOWN)
975*6881a400Schristos      or just return it.  */
976*6881a400Schristos 
977*6881a400Schristos   if (name != NULL && name[0] != '\0' && flag == CTF_ADD_ROOT
978*6881a400Schristos       && (type = ctf_lookup_by_rawname (fp, CTF_K_UNKNOWN, name)))
979*6881a400Schristos     {
980*6881a400Schristos       if (ctf_type_kind (fp, type) == CTF_K_UNKNOWN)
981*6881a400Schristos 	return type;
982*6881a400Schristos       else
983*6881a400Schristos 	{
984*6881a400Schristos 	  ctf_err_warn (fp, 1, ECTF_CONFLICT,
985*6881a400Schristos 			_("ctf_add_unknown: cannot add unknown type "
986*6881a400Schristos 			  "named %s: type of this name already defined"),
987*6881a400Schristos 			name ? name : _("(unnamed type)"));
988*6881a400Schristos 	  return (ctf_set_errno (fp, ECTF_CONFLICT));
989*6881a400Schristos 	}
990*6881a400Schristos     }
991*6881a400Schristos 
992*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, name, CTF_K_UNKNOWN, 0, &dtd)) == CTF_ERR)
993*6881a400Schristos     return CTF_ERR;		/* errno is set for us.  */
994*6881a400Schristos 
995*6881a400Schristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNKNOWN, flag, 0);
996*6881a400Schristos   dtd->dtd_data.ctt_type = 0;
997*6881a400Schristos 
998*6881a400Schristos   return type;
999*6881a400Schristos }
1000*6881a400Schristos 
1001*6881a400Schristos ctf_id_t
1002*6881a400Schristos ctf_add_typedef (ctf_dict_t *fp, uint32_t flag, const char *name,
10037d62b00eSchristos 		 ctf_id_t ref)
10047d62b00eSchristos {
10057d62b00eSchristos   ctf_dtdef_t *dtd;
10067d62b00eSchristos   ctf_id_t type;
1007*6881a400Schristos   ctf_dict_t *tmp = fp;
10087d62b00eSchristos 
10097d62b00eSchristos   if (ref == CTF_ERR || ref > CTF_MAX_TYPE)
10107d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
10117d62b00eSchristos 
1012*6881a400Schristos   if (name == NULL || name[0] == '\0')
1013*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NONAME));
1014*6881a400Schristos 
10157d62b00eSchristos   if (ref != 0 && ctf_lookup_by_id (&tmp, ref) == NULL)
10167d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
10177d62b00eSchristos 
1018*6881a400Schristos   if ((type = ctf_add_generic (fp, flag, name, CTF_K_TYPEDEF, 0,
10197d62b00eSchristos 			       &dtd)) == CTF_ERR)
10207d62b00eSchristos     return CTF_ERR;		/* errno is set for us.  */
10217d62b00eSchristos 
10227d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_TYPEDEF, flag, 0);
10237d62b00eSchristos   dtd->dtd_data.ctt_type = (uint32_t) ref;
10247d62b00eSchristos 
10257d62b00eSchristos   return type;
10267d62b00eSchristos }
10277d62b00eSchristos 
10287d62b00eSchristos ctf_id_t
1029*6881a400Schristos ctf_add_volatile (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref)
10307d62b00eSchristos {
10317d62b00eSchristos   return (ctf_add_reftype (fp, flag, ref, CTF_K_VOLATILE));
10327d62b00eSchristos }
10337d62b00eSchristos 
10347d62b00eSchristos ctf_id_t
1035*6881a400Schristos ctf_add_const (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref)
10367d62b00eSchristos {
10377d62b00eSchristos   return (ctf_add_reftype (fp, flag, ref, CTF_K_CONST));
10387d62b00eSchristos }
10397d62b00eSchristos 
10407d62b00eSchristos ctf_id_t
1041*6881a400Schristos ctf_add_restrict (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref)
10427d62b00eSchristos {
10437d62b00eSchristos   return (ctf_add_reftype (fp, flag, ref, CTF_K_RESTRICT));
10447d62b00eSchristos }
10457d62b00eSchristos 
10467d62b00eSchristos int
1047*6881a400Schristos ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
10487d62b00eSchristos 		    int value)
10497d62b00eSchristos {
10507d62b00eSchristos   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid);
1051*6881a400Schristos   unsigned char *old_vlen;
1052*6881a400Schristos   ctf_enum_t *en;
1053*6881a400Schristos   size_t i;
10547d62b00eSchristos 
10557d62b00eSchristos   uint32_t kind, vlen, root;
10567d62b00eSchristos 
10577d62b00eSchristos   if (name == NULL)
10587d62b00eSchristos     return (ctf_set_errno (fp, EINVAL));
10597d62b00eSchristos 
10607d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
10617d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
10627d62b00eSchristos 
10637d62b00eSchristos   if (dtd == NULL)
10647d62b00eSchristos     return (ctf_set_errno (fp, ECTF_BADID));
10657d62b00eSchristos 
10667d62b00eSchristos   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
10677d62b00eSchristos   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
10687d62b00eSchristos   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
10697d62b00eSchristos 
10707d62b00eSchristos   if (kind != CTF_K_ENUM)
10717d62b00eSchristos     return (ctf_set_errno (fp, ECTF_NOTENUM));
10727d62b00eSchristos 
10737d62b00eSchristos   if (vlen == CTF_MAX_VLEN)
10747d62b00eSchristos     return (ctf_set_errno (fp, ECTF_DTFULL));
10757d62b00eSchristos 
1076*6881a400Schristos   old_vlen = dtd->dtd_vlen;
1077*6881a400Schristos   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
1078*6881a400Schristos     return -1;					/* errno is set for us.  */
1079*6881a400Schristos   en = (ctf_enum_t *) dtd->dtd_vlen;
1080*6881a400Schristos 
1081*6881a400Schristos   if (dtd->dtd_vlen != old_vlen)
10827d62b00eSchristos     {
1083*6881a400Schristos       ptrdiff_t move = (signed char *) dtd->dtd_vlen - (signed char *) old_vlen;
1084*6881a400Schristos 
1085*6881a400Schristos       /* Remove pending refs in the old vlen region and reapply them.  */
1086*6881a400Schristos 
1087*6881a400Schristos       for (i = 0; i < vlen; i++)
1088*6881a400Schristos 	ctf_str_move_pending (fp, &en[i].cte_name, move);
1089*6881a400Schristos     }
1090*6881a400Schristos 
1091*6881a400Schristos   for (i = 0; i < vlen; i++)
1092*6881a400Schristos     if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
10937d62b00eSchristos       return (ctf_set_errno (fp, ECTF_DUPLICATE));
10947d62b00eSchristos 
1095*6881a400Schristos   en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
1096*6881a400Schristos   en[i].cte_value = value;
10977d62b00eSchristos 
1098*6881a400Schristos   if (en[i].cte_name == 0 && name != NULL && name[0] != '\0')
1099*6881a400Schristos     return -1;					/* errno is set for us. */
11007d62b00eSchristos 
11017d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
11027d62b00eSchristos 
11037d62b00eSchristos   fp->ctf_flags |= LCTF_DIRTY;
11047d62b00eSchristos 
11057d62b00eSchristos   return 0;
11067d62b00eSchristos }
11077d62b00eSchristos 
11087d62b00eSchristos int
1109*6881a400Schristos ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
11107d62b00eSchristos 		       ctf_id_t type, unsigned long bit_offset)
11117d62b00eSchristos {
11127d62b00eSchristos   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid);
11137d62b00eSchristos 
11147d62b00eSchristos   ssize_t msize, malign, ssize;
11157d62b00eSchristos   uint32_t kind, vlen, root;
1116*6881a400Schristos   size_t i;
1117*6881a400Schristos   int is_incomplete = 0;
1118*6881a400Schristos   unsigned char *old_vlen;
1119*6881a400Schristos   ctf_lmember_t *memb;
11207d62b00eSchristos 
11217d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
11227d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
11237d62b00eSchristos 
11247d62b00eSchristos   if (dtd == NULL)
11257d62b00eSchristos     return (ctf_set_errno (fp, ECTF_BADID));
11267d62b00eSchristos 
11277d62b00eSchristos   if (name != NULL && name[0] == '\0')
11287d62b00eSchristos     name = NULL;
11297d62b00eSchristos 
11307d62b00eSchristos   kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
11317d62b00eSchristos   root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
11327d62b00eSchristos   vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
11337d62b00eSchristos 
11347d62b00eSchristos   if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
11357d62b00eSchristos     return (ctf_set_errno (fp, ECTF_NOTSOU));
11367d62b00eSchristos 
11377d62b00eSchristos   if (vlen == CTF_MAX_VLEN)
11387d62b00eSchristos     return (ctf_set_errno (fp, ECTF_DTFULL));
11397d62b00eSchristos 
1140*6881a400Schristos   old_vlen = dtd->dtd_vlen;
1141*6881a400Schristos   if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
1142*6881a400Schristos     return -1;					/* errno is set for us.  */
1143*6881a400Schristos   memb = (ctf_lmember_t *) dtd->dtd_vlen;
1144*6881a400Schristos 
1145*6881a400Schristos   if (dtd->dtd_vlen != old_vlen)
1146*6881a400Schristos     {
1147*6881a400Schristos       ptrdiff_t move = (signed char *) dtd->dtd_vlen - (signed char *) old_vlen;
1148*6881a400Schristos 
1149*6881a400Schristos       /* Remove pending refs in the old vlen region and reapply them.  */
1150*6881a400Schristos 
1151*6881a400Schristos       for (i = 0; i < vlen; i++)
1152*6881a400Schristos 	ctf_str_move_pending (fp, &memb[i].ctlm_name, move);
1153*6881a400Schristos     }
1154*6881a400Schristos 
11557d62b00eSchristos   if (name != NULL)
11567d62b00eSchristos     {
1157*6881a400Schristos       for (i = 0; i < vlen; i++)
1158*6881a400Schristos 	if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
11597d62b00eSchristos 	  return (ctf_set_errno (fp, ECTF_DUPLICATE));
11607d62b00eSchristos     }
11617d62b00eSchristos 
11627d62b00eSchristos   if ((msize = ctf_type_size (fp, type)) < 0 ||
11637d62b00eSchristos       (malign = ctf_type_align (fp, type)) < 0)
11647d62b00eSchristos     {
11657d62b00eSchristos       /* The unimplemented type, and any type that resolves to it, has no size
11667d62b00eSchristos 	 and no alignment: it can correspond to any number of compiler-inserted
1167*6881a400Schristos 	 types.  We allow incomplete types through since they are routinely
1168*6881a400Schristos 	 added to the ends of structures, and can even be added elsewhere in
1169*6881a400Schristos 	 structures by the deduplicator.  They are assumed to be zero-size with
1170*6881a400Schristos 	 no alignment: this is often wrong, but problems can be avoided in this
1171*6881a400Schristos 	 case by explicitly specifying the size of the structure via the _sized
1172*6881a400Schristos 	 functions.  The deduplicator always does this.  */
11737d62b00eSchristos 
11747d62b00eSchristos       msize = 0;
11757d62b00eSchristos       malign = 0;
1176*6881a400Schristos       if (ctf_errno (fp) == ECTF_NONREPRESENTABLE)
11777d62b00eSchristos 	ctf_set_errno (fp, 0);
1178*6881a400Schristos       else if (ctf_errno (fp) == ECTF_INCOMPLETE)
1179*6881a400Schristos 	is_incomplete = 1;
11807d62b00eSchristos       else
11817d62b00eSchristos 	return -1;		/* errno is set for us.  */
11827d62b00eSchristos     }
11837d62b00eSchristos 
1184*6881a400Schristos   memb[vlen].ctlm_name = ctf_str_add_pending (fp, name, &memb[vlen].ctlm_name);
1185*6881a400Schristos   memb[vlen].ctlm_type = type;
1186*6881a400Schristos   if (memb[vlen].ctlm_name == 0 && name != NULL && name[0] != '\0')
1187*6881a400Schristos     return -1;			/* errno is set for us.  */
11887d62b00eSchristos 
11897d62b00eSchristos   if (kind == CTF_K_STRUCT && vlen != 0)
11907d62b00eSchristos     {
11917d62b00eSchristos       if (bit_offset == (unsigned long) - 1)
11927d62b00eSchristos 	{
11937d62b00eSchristos 	  /* Natural alignment.  */
11947d62b00eSchristos 
1195*6881a400Schristos 	  ctf_id_t ltype = ctf_type_resolve (fp, memb[vlen - 1].ctlm_type);
1196*6881a400Schristos 	  size_t off = CTF_LMEM_OFFSET(&memb[vlen - 1]);
11977d62b00eSchristos 
11987d62b00eSchristos 	  ctf_encoding_t linfo;
11997d62b00eSchristos 	  ssize_t lsize;
12007d62b00eSchristos 
12017d62b00eSchristos 	  /* Propagate any error from ctf_type_resolve.  If the last member was
12027d62b00eSchristos 	     of unimplemented type, this may be -ECTF_NONREPRESENTABLE: we
12037d62b00eSchristos 	     cannot insert right after such a member without explicit offset
12047d62b00eSchristos 	     specification, because its alignment and size is not known.  */
12057d62b00eSchristos 	  if (ltype == CTF_ERR)
12067d62b00eSchristos 	    return -1;	/* errno is set for us.  */
1207*6881a400Schristos 
1208*6881a400Schristos 	  if (is_incomplete)
1209*6881a400Schristos 	    {
1210*6881a400Schristos 	      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
1211*6881a400Schristos 			    _("ctf_add_member_offset: cannot add member %s of "
1212*6881a400Schristos 			      "incomplete type %lx to struct %lx without "
1213*6881a400Schristos 			      "specifying explicit offset\n"),
1214*6881a400Schristos 			    name ? name : _("(unnamed member)"), type, souid);
1215*6881a400Schristos 	      return (ctf_set_errno (fp, ECTF_INCOMPLETE));
12167d62b00eSchristos 	    }
12177d62b00eSchristos 
12187d62b00eSchristos 	  if (ctf_type_encoding (fp, ltype, &linfo) == 0)
12197d62b00eSchristos 	    off += linfo.cte_bits;
12207d62b00eSchristos 	  else if ((lsize = ctf_type_size (fp, ltype)) > 0)
12217d62b00eSchristos 	    off += lsize * CHAR_BIT;
1222*6881a400Schristos 	  else if (lsize == -1 && ctf_errno (fp) == ECTF_INCOMPLETE)
1223*6881a400Schristos 	    {
1224*6881a400Schristos 	      const char *lname = ctf_strraw (fp, memb[vlen - 1].ctlm_name);
1225*6881a400Schristos 
1226*6881a400Schristos 	      ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
1227*6881a400Schristos 			    _("ctf_add_member_offset: cannot add member %s of "
1228*6881a400Schristos 			      "type %lx to struct %lx without specifying "
1229*6881a400Schristos 			      "explicit offset after member %s of type %lx, "
1230*6881a400Schristos 			      "which is an incomplete type\n"),
1231*6881a400Schristos 			    name ? name : _("(unnamed member)"), type, souid,
1232*6881a400Schristos 			    lname ? lname : _("(unnamed member)"), ltype);
1233*6881a400Schristos 	      return -1;			/* errno is set for us.  */
1234*6881a400Schristos 	    }
12357d62b00eSchristos 
12367d62b00eSchristos 	  /* Round up the offset of the end of the last member to
12377d62b00eSchristos 	     the next byte boundary, convert 'off' to bytes, and
12387d62b00eSchristos 	     then round it up again to the next multiple of the
12397d62b00eSchristos 	     alignment required by the new member.  Finally,
12407d62b00eSchristos 	     convert back to bits and store the result in
12417d62b00eSchristos 	     dmd_offset.  Technically we could do more efficient
12427d62b00eSchristos 	     packing if the new member is a bit-field, but we're
12437d62b00eSchristos 	     the "compiler" and ANSI says we can do as we choose.  */
12447d62b00eSchristos 
12457d62b00eSchristos 	  off = roundup (off, CHAR_BIT) / CHAR_BIT;
12467d62b00eSchristos 	  off = roundup (off, MAX (malign, 1));
1247*6881a400Schristos 	  memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (off * CHAR_BIT);
1248*6881a400Schristos 	  memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (off * CHAR_BIT);
12497d62b00eSchristos 	  ssize = off + msize;
12507d62b00eSchristos 	}
12517d62b00eSchristos       else
12527d62b00eSchristos 	{
12537d62b00eSchristos 	  /* Specified offset in bits.  */
12547d62b00eSchristos 
1255*6881a400Schristos 	  memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (bit_offset);
1256*6881a400Schristos 	  memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (bit_offset);
12577d62b00eSchristos 	  ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
12587d62b00eSchristos 	  ssize = MAX (ssize, ((signed) bit_offset / CHAR_BIT) + msize);
12597d62b00eSchristos 	}
12607d62b00eSchristos     }
12617d62b00eSchristos   else
12627d62b00eSchristos     {
1263*6881a400Schristos       memb[vlen].ctlm_offsethi = 0;
1264*6881a400Schristos       memb[vlen].ctlm_offsetlo = 0;
12657d62b00eSchristos       ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL);
12667d62b00eSchristos       ssize = MAX (ssize, msize);
12677d62b00eSchristos     }
12687d62b00eSchristos 
12697d62b00eSchristos   dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
12707d62b00eSchristos   dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize);
12717d62b00eSchristos   dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize);
12727d62b00eSchristos   dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
12737d62b00eSchristos 
12747d62b00eSchristos   fp->ctf_flags |= LCTF_DIRTY;
12757d62b00eSchristos   return 0;
12767d62b00eSchristos }
12777d62b00eSchristos 
12787d62b00eSchristos int
1279*6881a400Schristos ctf_add_member_encoded (ctf_dict_t *fp, ctf_id_t souid, const char *name,
12807d62b00eSchristos 			ctf_id_t type, unsigned long bit_offset,
12817d62b00eSchristos 			const ctf_encoding_t encoding)
12827d62b00eSchristos {
12837d62b00eSchristos   ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
12847d62b00eSchristos   int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
12857d62b00eSchristos   int otype = type;
12867d62b00eSchristos 
12877d62b00eSchristos   if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
12887d62b00eSchristos     return (ctf_set_errno (fp, ECTF_NOTINTFP));
12897d62b00eSchristos 
12907d62b00eSchristos   if ((type = ctf_add_slice (fp, CTF_ADD_NONROOT, otype, &encoding)) == CTF_ERR)
12917d62b00eSchristos     return -1;			/* errno is set for us.  */
12927d62b00eSchristos 
12937d62b00eSchristos   return ctf_add_member_offset (fp, souid, name, type, bit_offset);
12947d62b00eSchristos }
12957d62b00eSchristos 
12967d62b00eSchristos int
1297*6881a400Schristos ctf_add_member (ctf_dict_t *fp, ctf_id_t souid, const char *name,
12987d62b00eSchristos 		ctf_id_t type)
12997d62b00eSchristos {
13007d62b00eSchristos   return ctf_add_member_offset (fp, souid, name, type, (unsigned long) - 1);
13017d62b00eSchristos }
13027d62b00eSchristos 
13037d62b00eSchristos int
1304*6881a400Schristos ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
13057d62b00eSchristos {
13067d62b00eSchristos   ctf_dvdef_t *dvd;
1307*6881a400Schristos   ctf_dict_t *tmp = fp;
13087d62b00eSchristos 
13097d62b00eSchristos   if (!(fp->ctf_flags & LCTF_RDWR))
13107d62b00eSchristos     return (ctf_set_errno (fp, ECTF_RDONLY));
13117d62b00eSchristos 
13127d62b00eSchristos   if (ctf_dvd_lookup (fp, name) != NULL)
13137d62b00eSchristos     return (ctf_set_errno (fp, ECTF_DUPLICATE));
13147d62b00eSchristos 
13157d62b00eSchristos   if (ctf_lookup_by_id (&tmp, ref) == NULL)
13167d62b00eSchristos     return -1;			/* errno is set for us.  */
13177d62b00eSchristos 
13187d62b00eSchristos   /* Make sure this type is representable.  */
13197d62b00eSchristos   if ((ctf_type_resolve (fp, ref) == CTF_ERR)
13207d62b00eSchristos       && (ctf_errno (fp) == ECTF_NONREPRESENTABLE))
13217d62b00eSchristos     return -1;
13227d62b00eSchristos 
13237d62b00eSchristos   if ((dvd = malloc (sizeof (ctf_dvdef_t))) == NULL)
13247d62b00eSchristos     return (ctf_set_errno (fp, EAGAIN));
13257d62b00eSchristos 
13267d62b00eSchristos   if (name != NULL && (dvd->dvd_name = strdup (name)) == NULL)
13277d62b00eSchristos     {
13287d62b00eSchristos       free (dvd);
13297d62b00eSchristos       return (ctf_set_errno (fp, EAGAIN));
13307d62b00eSchristos     }
13317d62b00eSchristos   dvd->dvd_type = ref;
13327d62b00eSchristos   dvd->dvd_snapshots = fp->ctf_snapshots;
13337d62b00eSchristos 
13347d62b00eSchristos   if (ctf_dvd_insert (fp, dvd) < 0)
13357d62b00eSchristos     {
13367d62b00eSchristos       free (dvd->dvd_name);
13377d62b00eSchristos       free (dvd);
13387d62b00eSchristos       return -1;			/* errno is set for us.  */
13397d62b00eSchristos     }
13407d62b00eSchristos 
13417d62b00eSchristos   fp->ctf_flags |= LCTF_DIRTY;
13427d62b00eSchristos   return 0;
13437d62b00eSchristos }
13447d62b00eSchristos 
1345*6881a400Schristos int
1346*6881a400Schristos ctf_add_funcobjt_sym (ctf_dict_t *fp, int is_function, const char *name, ctf_id_t id)
1347*6881a400Schristos {
1348*6881a400Schristos   ctf_dict_t *tmp = fp;
1349*6881a400Schristos   char *dupname;
1350*6881a400Schristos   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
1351*6881a400Schristos 
1352*6881a400Schristos   if (!(fp->ctf_flags & LCTF_RDWR))
1353*6881a400Schristos     return (ctf_set_errno (fp, ECTF_RDONLY));
1354*6881a400Schristos 
1355*6881a400Schristos   if (ctf_dynhash_lookup (fp->ctf_objthash, name) != NULL ||
1356*6881a400Schristos       ctf_dynhash_lookup (fp->ctf_funchash, name) != NULL)
1357*6881a400Schristos     return (ctf_set_errno (fp, ECTF_DUPLICATE));
1358*6881a400Schristos 
1359*6881a400Schristos   if (ctf_lookup_by_id (&tmp, id) == NULL)
1360*6881a400Schristos     return -1;                                  /* errno is set for us.  */
1361*6881a400Schristos 
1362*6881a400Schristos   if (is_function && ctf_type_kind (fp, id) != CTF_K_FUNCTION)
1363*6881a400Schristos     return (ctf_set_errno (fp, ECTF_NOTFUNC));
1364*6881a400Schristos 
1365*6881a400Schristos   if ((dupname = strdup (name)) == NULL)
1366*6881a400Schristos     return (ctf_set_errno (fp, ENOMEM));
1367*6881a400Schristos 
1368*6881a400Schristos   if (ctf_dynhash_insert (h, dupname, (void *) (uintptr_t) id) < 0)
1369*6881a400Schristos     {
1370*6881a400Schristos       free (dupname);
1371*6881a400Schristos       return (ctf_set_errno (fp, ENOMEM));
1372*6881a400Schristos     }
1373*6881a400Schristos   return 0;
1374*6881a400Schristos }
1375*6881a400Schristos 
1376*6881a400Schristos int
1377*6881a400Schristos ctf_add_objt_sym (ctf_dict_t *fp, const char *name, ctf_id_t id)
1378*6881a400Schristos {
1379*6881a400Schristos   return (ctf_add_funcobjt_sym (fp, 0, name, id));
1380*6881a400Schristos }
1381*6881a400Schristos 
1382*6881a400Schristos int
1383*6881a400Schristos ctf_add_func_sym (ctf_dict_t *fp, const char *name, ctf_id_t id)
1384*6881a400Schristos {
1385*6881a400Schristos   return (ctf_add_funcobjt_sym (fp, 1, name, id));
1386*6881a400Schristos }
1387*6881a400Schristos 
13887d62b00eSchristos typedef struct ctf_bundle
13897d62b00eSchristos {
1390*6881a400Schristos   ctf_dict_t *ctb_dict;		/* CTF dict handle.  */
13917d62b00eSchristos   ctf_id_t ctb_type;		/* CTF type identifier.  */
13927d62b00eSchristos   ctf_dtdef_t *ctb_dtd;		/* CTF dynamic type definition (if any).  */
13937d62b00eSchristos } ctf_bundle_t;
13947d62b00eSchristos 
13957d62b00eSchristos static int
13967d62b00eSchristos enumcmp (const char *name, int value, void *arg)
13977d62b00eSchristos {
13987d62b00eSchristos   ctf_bundle_t *ctb = arg;
13997d62b00eSchristos   int bvalue;
14007d62b00eSchristos 
1401*6881a400Schristos   if (ctf_enum_value (ctb->ctb_dict, ctb->ctb_type, name, &bvalue) < 0)
14027d62b00eSchristos     {
1403*6881a400Schristos       ctf_err_warn (ctb->ctb_dict, 0, 0,
14047d62b00eSchristos 		    _("conflict due to enum %s iteration error"), name);
14057d62b00eSchristos       return 1;
14067d62b00eSchristos     }
14077d62b00eSchristos   if (value != bvalue)
14087d62b00eSchristos     {
1409*6881a400Schristos       ctf_err_warn (ctb->ctb_dict, 1, ECTF_CONFLICT,
14107d62b00eSchristos 		    _("conflict due to enum value change: %i versus %i"),
14117d62b00eSchristos 		    value, bvalue);
14127d62b00eSchristos       return 1;
14137d62b00eSchristos     }
14147d62b00eSchristos   return 0;
14157d62b00eSchristos }
14167d62b00eSchristos 
14177d62b00eSchristos static int
14187d62b00eSchristos enumadd (const char *name, int value, void *arg)
14197d62b00eSchristos {
14207d62b00eSchristos   ctf_bundle_t *ctb = arg;
14217d62b00eSchristos 
1422*6881a400Schristos   return (ctf_add_enumerator (ctb->ctb_dict, ctb->ctb_type,
14237d62b00eSchristos 			      name, value) < 0);
14247d62b00eSchristos }
14257d62b00eSchristos 
14267d62b00eSchristos static int
14277d62b00eSchristos membcmp (const char *name, ctf_id_t type _libctf_unused_, unsigned long offset,
14287d62b00eSchristos 	 void *arg)
14297d62b00eSchristos {
14307d62b00eSchristos   ctf_bundle_t *ctb = arg;
14317d62b00eSchristos   ctf_membinfo_t ctm;
14327d62b00eSchristos 
14337d62b00eSchristos   /* Don't check nameless members (e.g. anonymous structs/unions) against each
14347d62b00eSchristos      other.  */
14357d62b00eSchristos   if (name[0] == 0)
14367d62b00eSchristos     return 0;
14377d62b00eSchristos 
1438*6881a400Schristos   if (ctf_member_info (ctb->ctb_dict, ctb->ctb_type, name, &ctm) < 0)
14397d62b00eSchristos     {
1440*6881a400Schristos       ctf_err_warn (ctb->ctb_dict, 0, 0,
14417d62b00eSchristos 		    _("conflict due to struct member %s iteration error"),
14427d62b00eSchristos 		    name);
14437d62b00eSchristos       return 1;
14447d62b00eSchristos     }
14457d62b00eSchristos   if (ctm.ctm_offset != offset)
14467d62b00eSchristos     {
1447*6881a400Schristos       ctf_err_warn (ctb->ctb_dict, 1, ECTF_CONFLICT,
14487d62b00eSchristos 		    _("conflict due to struct member %s offset change: "
14497d62b00eSchristos 		      "%lx versus %lx"),
14507d62b00eSchristos 		    name, ctm.ctm_offset, offset);
14517d62b00eSchristos       return 1;
14527d62b00eSchristos     }
14537d62b00eSchristos   return 0;
14547d62b00eSchristos }
14557d62b00eSchristos 
1456*6881a400Schristos /* Record the correspondence between a source and ctf_add_type()-added
1457*6881a400Schristos    destination type: both types are translated into parent type IDs if need be,
1458*6881a400Schristos    so they relate to the actual dictionary they are in.  Outside controlled
1459*6881a400Schristos    circumstances (like linking) it is probably not useful to do more than
1460*6881a400Schristos    compare these pointers, since there is nothing stopping the user closing the
1461*6881a400Schristos    source dict whenever they want to.
14627d62b00eSchristos 
1463*6881a400Schristos    Our OOM handling here is just to not do anything, because this is called deep
1464*6881a400Schristos    enough in the call stack that doing anything useful is painfully difficult:
1465*6881a400Schristos    the worst consequence if we do OOM is a bit of type duplication anyway.  */
14667d62b00eSchristos 
1467*6881a400Schristos static void
1468*6881a400Schristos ctf_add_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type,
1469*6881a400Schristos 		      ctf_dict_t *dst_fp, ctf_id_t dst_type)
14707d62b00eSchristos {
1471*6881a400Schristos   if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent)
1472*6881a400Schristos     src_fp = src_fp->ctf_parent;
1473*6881a400Schristos 
1474*6881a400Schristos   src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type);
1475*6881a400Schristos 
1476*6881a400Schristos   if (LCTF_TYPE_ISPARENT (dst_fp, dst_type) && dst_fp->ctf_parent)
1477*6881a400Schristos     dst_fp = dst_fp->ctf_parent;
1478*6881a400Schristos 
1479*6881a400Schristos   dst_type = LCTF_TYPE_TO_INDEX(dst_fp, dst_type);
1480*6881a400Schristos 
1481*6881a400Schristos   if (dst_fp->ctf_link_type_mapping == NULL)
1482*6881a400Schristos     {
1483*6881a400Schristos       ctf_hash_fun f = ctf_hash_type_key;
1484*6881a400Schristos       ctf_hash_eq_fun e = ctf_hash_eq_type_key;
1485*6881a400Schristos 
1486*6881a400Schristos       if ((dst_fp->ctf_link_type_mapping = ctf_dynhash_create (f, e, free,
1487*6881a400Schristos 							       NULL)) == NULL)
1488*6881a400Schristos 	return;
14897d62b00eSchristos     }
14907d62b00eSchristos 
1491*6881a400Schristos   ctf_link_type_key_t *key;
1492*6881a400Schristos   key = calloc (1, sizeof (struct ctf_link_type_key));
1493*6881a400Schristos   if (!key)
1494*6881a400Schristos     return;
14957d62b00eSchristos 
1496*6881a400Schristos   key->cltk_fp = src_fp;
1497*6881a400Schristos   key->cltk_idx = src_type;
14987d62b00eSchristos 
1499*6881a400Schristos   /* No OOM checking needed, because if this doesn't work the worst we'll do is
1500*6881a400Schristos      add a few more duplicate types (which will probably run out of memory
1501*6881a400Schristos      anyway).  */
1502*6881a400Schristos   ctf_dynhash_insert (dst_fp->ctf_link_type_mapping, key,
1503*6881a400Schristos 		      (void *) (uintptr_t) dst_type);
15047d62b00eSchristos }
15057d62b00eSchristos 
1506*6881a400Schristos /* Look up a type mapping: return 0 if none.  The DST_FP is modified to point to
1507*6881a400Schristos    the parent if need be.  The ID returned is from the dst_fp's perspective.  */
15087d62b00eSchristos static ctf_id_t
1509*6881a400Schristos ctf_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, ctf_dict_t **dst_fp)
1510*6881a400Schristos {
1511*6881a400Schristos   ctf_link_type_key_t key;
1512*6881a400Schristos   ctf_dict_t *target_fp = *dst_fp;
1513*6881a400Schristos   ctf_id_t dst_type = 0;
1514*6881a400Schristos 
1515*6881a400Schristos   if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent)
1516*6881a400Schristos     src_fp = src_fp->ctf_parent;
1517*6881a400Schristos 
1518*6881a400Schristos   src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type);
1519*6881a400Schristos   key.cltk_fp = src_fp;
1520*6881a400Schristos   key.cltk_idx = src_type;
1521*6881a400Schristos 
1522*6881a400Schristos   if (target_fp->ctf_link_type_mapping)
1523*6881a400Schristos     dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping,
1524*6881a400Schristos 					       &key);
1525*6881a400Schristos 
1526*6881a400Schristos   if (dst_type != 0)
1527*6881a400Schristos     {
1528*6881a400Schristos       dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type,
1529*6881a400Schristos 				     target_fp->ctf_parent != NULL);
1530*6881a400Schristos       *dst_fp = target_fp;
1531*6881a400Schristos       return dst_type;
1532*6881a400Schristos     }
1533*6881a400Schristos 
1534*6881a400Schristos   if (target_fp->ctf_parent)
1535*6881a400Schristos     target_fp = target_fp->ctf_parent;
1536*6881a400Schristos   else
1537*6881a400Schristos     return 0;
1538*6881a400Schristos 
1539*6881a400Schristos   if (target_fp->ctf_link_type_mapping)
1540*6881a400Schristos     dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping,
1541*6881a400Schristos 					       &key);
1542*6881a400Schristos 
1543*6881a400Schristos   if (dst_type)
1544*6881a400Schristos     dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type,
1545*6881a400Schristos 				   target_fp->ctf_parent != NULL);
1546*6881a400Schristos 
1547*6881a400Schristos   *dst_fp = target_fp;
1548*6881a400Schristos   return dst_type;
1549*6881a400Schristos }
1550*6881a400Schristos 
1551*6881a400Schristos /* The ctf_add_type routine is used to copy a type from a source CTF dictionary
1552*6881a400Schristos    to a dynamic destination dictionary.  This routine operates recursively by
1553*6881a400Schristos    following the source type's links and embedded member types.  If the
1554*6881a400Schristos    destination dict already contains a named type which has the same attributes,
1555*6881a400Schristos    then we succeed and return this type but no changes occur.  */
1556*6881a400Schristos static ctf_id_t
1557*6881a400Schristos ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type,
1558*6881a400Schristos 		       ctf_dict_t *proc_tracking_fp)
15597d62b00eSchristos {
15607d62b00eSchristos   ctf_id_t dst_type = CTF_ERR;
15617d62b00eSchristos   uint32_t dst_kind = CTF_K_UNKNOWN;
1562*6881a400Schristos   ctf_dict_t *tmp_fp = dst_fp;
15637d62b00eSchristos   ctf_id_t tmp;
15647d62b00eSchristos 
15657d62b00eSchristos   const char *name;
15667d62b00eSchristos   uint32_t kind, forward_kind, flag, vlen;
15677d62b00eSchristos 
15687d62b00eSchristos   const ctf_type_t *src_tp, *dst_tp;
15697d62b00eSchristos   ctf_bundle_t src, dst;
15707d62b00eSchristos   ctf_encoding_t src_en, dst_en;
15717d62b00eSchristos   ctf_arinfo_t src_ar, dst_ar;
15727d62b00eSchristos 
15737d62b00eSchristos   ctf_funcinfo_t ctc;
15747d62b00eSchristos 
15757d62b00eSchristos   ctf_id_t orig_src_type = src_type;
15767d62b00eSchristos 
15777d62b00eSchristos   if (!(dst_fp->ctf_flags & LCTF_RDWR))
15787d62b00eSchristos     return (ctf_set_errno (dst_fp, ECTF_RDONLY));
15797d62b00eSchristos 
15807d62b00eSchristos   if ((src_tp = ctf_lookup_by_id (&src_fp, src_type)) == NULL)
15817d62b00eSchristos     return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
15827d62b00eSchristos 
15837d62b00eSchristos   if ((ctf_type_resolve (src_fp, src_type) == CTF_ERR)
15847d62b00eSchristos       && (ctf_errno (src_fp) == ECTF_NONREPRESENTABLE))
15857d62b00eSchristos     return (ctf_set_errno (dst_fp, ECTF_NONREPRESENTABLE));
15867d62b00eSchristos 
15877d62b00eSchristos   name = ctf_strptr (src_fp, src_tp->ctt_name);
15887d62b00eSchristos   kind = LCTF_INFO_KIND (src_fp, src_tp->ctt_info);
15897d62b00eSchristos   flag = LCTF_INFO_ISROOT (src_fp, src_tp->ctt_info);
15907d62b00eSchristos   vlen = LCTF_INFO_VLEN (src_fp, src_tp->ctt_info);
15917d62b00eSchristos 
15927d62b00eSchristos   /* If this is a type we are currently in the middle of adding, hand it
15937d62b00eSchristos      straight back.  (This lets us handle self-referential structures without
15947d62b00eSchristos      considering forwards and empty structures the same as their completed
15957d62b00eSchristos      forms.)  */
15967d62b00eSchristos 
15977d62b00eSchristos   tmp = ctf_type_mapping (src_fp, src_type, &tmp_fp);
15987d62b00eSchristos 
15997d62b00eSchristos   if (tmp != 0)
16007d62b00eSchristos     {
16017d62b00eSchristos       if (ctf_dynhash_lookup (proc_tracking_fp->ctf_add_processing,
16027d62b00eSchristos 			      (void *) (uintptr_t) src_type))
16037d62b00eSchristos 	return tmp;
16047d62b00eSchristos 
1605*6881a400Schristos       /* If this type has already been added from this dictionary, and is the
1606*6881a400Schristos 	 same kind and (if a struct or union) has the same number of members,
1607*6881a400Schristos 	 hand it straight back.  */
16087d62b00eSchristos 
16097d62b00eSchristos       if (ctf_type_kind_unsliced (tmp_fp, tmp) == (int) kind)
16107d62b00eSchristos 	{
16117d62b00eSchristos 	  if (kind == CTF_K_STRUCT || kind == CTF_K_UNION
16127d62b00eSchristos 	      || kind == CTF_K_ENUM)
16137d62b00eSchristos 	    {
16147d62b00eSchristos 	      if ((dst_tp = ctf_lookup_by_id (&tmp_fp, dst_type)) != NULL)
16157d62b00eSchristos 		if (vlen == LCTF_INFO_VLEN (tmp_fp, dst_tp->ctt_info))
16167d62b00eSchristos 		  return tmp;
16177d62b00eSchristos 	    }
16187d62b00eSchristos 	  else
16197d62b00eSchristos 	    return tmp;
16207d62b00eSchristos 	}
16217d62b00eSchristos     }
16227d62b00eSchristos 
16237d62b00eSchristos   forward_kind = kind;
16247d62b00eSchristos   if (kind == CTF_K_FORWARD)
16257d62b00eSchristos     forward_kind = src_tp->ctt_type;
16267d62b00eSchristos 
1627*6881a400Schristos   /* If the source type has a name and is a root type (visible at the top-level
1628*6881a400Schristos      scope), lookup the name in the destination dictionary and verify that it is
1629*6881a400Schristos      of the same kind before we do anything else.  */
16307d62b00eSchristos 
16317d62b00eSchristos   if ((flag & CTF_ADD_ROOT) && name[0] != '\0'
16327d62b00eSchristos       && (tmp = ctf_lookup_by_rawname (dst_fp, forward_kind, name)) != 0)
16337d62b00eSchristos     {
16347d62b00eSchristos       dst_type = tmp;
16357d62b00eSchristos       dst_kind = ctf_type_kind_unsliced (dst_fp, dst_type);
16367d62b00eSchristos     }
16377d62b00eSchristos 
16387d62b00eSchristos   /* If an identically named dst_type exists, fail with ECTF_CONFLICT
16397d62b00eSchristos      unless dst_type is a forward declaration and src_type is a struct,
16407d62b00eSchristos      union, or enum (i.e. the definition of the previous forward decl).
16417d62b00eSchristos 
16427d62b00eSchristos      We also allow addition in the opposite order (addition of a forward when a
16437d62b00eSchristos      struct, union, or enum already exists), which is a NOP and returns the
16447d62b00eSchristos      already-present struct, union, or enum.  */
16457d62b00eSchristos 
16467d62b00eSchristos   if (dst_type != CTF_ERR && dst_kind != kind)
16477d62b00eSchristos     {
16487d62b00eSchristos       if (kind == CTF_K_FORWARD
16497d62b00eSchristos 	  && (dst_kind == CTF_K_ENUM || dst_kind == CTF_K_STRUCT
16507d62b00eSchristos 	      || dst_kind == CTF_K_UNION))
16517d62b00eSchristos 	{
16527d62b00eSchristos 	  ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
16537d62b00eSchristos 	  return dst_type;
16547d62b00eSchristos 	}
16557d62b00eSchristos 
16567d62b00eSchristos       if (dst_kind != CTF_K_FORWARD
16577d62b00eSchristos 	  || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT
16587d62b00eSchristos 	      && kind != CTF_K_UNION))
16597d62b00eSchristos 	{
16607d62b00eSchristos 	  ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
1661*6881a400Schristos 			_("ctf_add_type: conflict for type %s: "
16627d62b00eSchristos 			  "kinds differ, new: %i; old (ID %lx): %i"),
16637d62b00eSchristos 			name, kind, dst_type, dst_kind);
16647d62b00eSchristos 	  return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
16657d62b00eSchristos 	}
16667d62b00eSchristos     }
16677d62b00eSchristos 
16687d62b00eSchristos   /* We take special action for an integer, float, or slice since it is
16697d62b00eSchristos      described not only by its name but also its encoding.  For integers,
16707d62b00eSchristos      bit-fields exploit this degeneracy.  */
16717d62b00eSchristos 
16727d62b00eSchristos   if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT || kind == CTF_K_SLICE)
16737d62b00eSchristos     {
16747d62b00eSchristos       if (ctf_type_encoding (src_fp, src_type, &src_en) != 0)
16757d62b00eSchristos 	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
16767d62b00eSchristos 
16777d62b00eSchristos       if (dst_type != CTF_ERR)
16787d62b00eSchristos 	{
1679*6881a400Schristos 	  ctf_dict_t *fp = dst_fp;
16807d62b00eSchristos 
16817d62b00eSchristos 	  if ((dst_tp = ctf_lookup_by_id (&fp, dst_type)) == NULL)
16827d62b00eSchristos 	    return CTF_ERR;
16837d62b00eSchristos 
16847d62b00eSchristos 	  if (ctf_type_encoding (dst_fp, dst_type, &dst_en) != 0)
16857d62b00eSchristos 	    return CTF_ERR;			/* errno set for us.  */
16867d62b00eSchristos 
16877d62b00eSchristos 	  if (LCTF_INFO_ISROOT (fp, dst_tp->ctt_info) & CTF_ADD_ROOT)
16887d62b00eSchristos 	    {
16897d62b00eSchristos 	      /* The type that we found in the hash is also root-visible.  If
16907d62b00eSchristos 		 the two types match then use the existing one; otherwise,
16917d62b00eSchristos 		 declare a conflict.  Note: slices are not certain to match
16927d62b00eSchristos 		 even if there is no conflict: we must check the contained type
16937d62b00eSchristos 		 too.  */
16947d62b00eSchristos 
16957d62b00eSchristos 	      if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0)
16967d62b00eSchristos 		{
16977d62b00eSchristos 		  if (kind != CTF_K_SLICE)
16987d62b00eSchristos 		    {
16997d62b00eSchristos 		      ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
17007d62b00eSchristos 		      return dst_type;
17017d62b00eSchristos 		    }
17027d62b00eSchristos 		}
17037d62b00eSchristos 	      else
17047d62b00eSchristos 		  {
17057d62b00eSchristos 		    return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
17067d62b00eSchristos 		  }
17077d62b00eSchristos 	    }
17087d62b00eSchristos 	  else
17097d62b00eSchristos 	    {
17107d62b00eSchristos 	      /* We found a non-root-visible type in the hash.  If its encoding
17117d62b00eSchristos 		 is the same, we can reuse it, unless it is a slice.  */
17127d62b00eSchristos 
17137d62b00eSchristos 	      if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0)
17147d62b00eSchristos 		{
17157d62b00eSchristos 		  if (kind != CTF_K_SLICE)
17167d62b00eSchristos 		    {
17177d62b00eSchristos 		      ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
17187d62b00eSchristos 		      return dst_type;
17197d62b00eSchristos 		    }
17207d62b00eSchristos 		}
17217d62b00eSchristos 	    }
17227d62b00eSchristos 	}
17237d62b00eSchristos     }
17247d62b00eSchristos 
1725*6881a400Schristos   src.ctb_dict = src_fp;
17267d62b00eSchristos   src.ctb_type = src_type;
17277d62b00eSchristos   src.ctb_dtd = NULL;
17287d62b00eSchristos 
1729*6881a400Schristos   dst.ctb_dict = dst_fp;
17307d62b00eSchristos   dst.ctb_type = dst_type;
17317d62b00eSchristos   dst.ctb_dtd = NULL;
17327d62b00eSchristos 
17337d62b00eSchristos   /* Now perform kind-specific processing.  If dst_type is CTF_ERR, then we add
17347d62b00eSchristos      a new type with the same properties as src_type to dst_fp.  If dst_type is
17357d62b00eSchristos      not CTF_ERR, then we verify that dst_type has the same attributes as
17367d62b00eSchristos      src_type.  We recurse for embedded references.  Before we start, we note
17377d62b00eSchristos      that we are processing this type, to prevent infinite recursion: we do not
17387d62b00eSchristos      re-process any type that appears in this list.  The list is emptied
17397d62b00eSchristos      wholesale at the end of processing everything in this recursive stack.  */
17407d62b00eSchristos 
17417d62b00eSchristos   if (ctf_dynhash_insert (proc_tracking_fp->ctf_add_processing,
17427d62b00eSchristos 			  (void *) (uintptr_t) src_type, (void *) 1) < 0)
17437d62b00eSchristos     return ctf_set_errno (dst_fp, ENOMEM);
17447d62b00eSchristos 
17457d62b00eSchristos   switch (kind)
17467d62b00eSchristos     {
17477d62b00eSchristos     case CTF_K_INTEGER:
17487d62b00eSchristos       /*  If we found a match we will have either returned it or declared a
17497d62b00eSchristos 	  conflict.  */
17507d62b00eSchristos       dst_type = ctf_add_integer (dst_fp, flag, name, &src_en);
17517d62b00eSchristos       break;
17527d62b00eSchristos 
17537d62b00eSchristos     case CTF_K_FLOAT:
17547d62b00eSchristos       /* If we found a match we will have either returned it or declared a
17557d62b00eSchristos        conflict.  */
17567d62b00eSchristos       dst_type = ctf_add_float (dst_fp, flag, name, &src_en);
17577d62b00eSchristos       break;
17587d62b00eSchristos 
17597d62b00eSchristos     case CTF_K_SLICE:
17607d62b00eSchristos       /* We have checked for conflicting encodings: now try to add the
17617d62b00eSchristos 	 contained type.  */
17627d62b00eSchristos       src_type = ctf_type_reference (src_fp, src_type);
17637d62b00eSchristos       src_type = ctf_add_type_internal (dst_fp, src_fp, src_type,
17647d62b00eSchristos 					proc_tracking_fp);
17657d62b00eSchristos 
17667d62b00eSchristos       if (src_type == CTF_ERR)
17677d62b00eSchristos 	return CTF_ERR;				/* errno is set for us.  */
17687d62b00eSchristos 
17697d62b00eSchristos       dst_type = ctf_add_slice (dst_fp, flag, src_type, &src_en);
17707d62b00eSchristos       break;
17717d62b00eSchristos 
17727d62b00eSchristos     case CTF_K_POINTER:
17737d62b00eSchristos     case CTF_K_VOLATILE:
17747d62b00eSchristos     case CTF_K_CONST:
17757d62b00eSchristos     case CTF_K_RESTRICT:
17767d62b00eSchristos       src_type = ctf_type_reference (src_fp, src_type);
17777d62b00eSchristos       src_type = ctf_add_type_internal (dst_fp, src_fp, src_type,
17787d62b00eSchristos 					proc_tracking_fp);
17797d62b00eSchristos 
17807d62b00eSchristos       if (src_type == CTF_ERR)
17817d62b00eSchristos 	return CTF_ERR;				/* errno is set for us.  */
17827d62b00eSchristos 
17837d62b00eSchristos       dst_type = ctf_add_reftype (dst_fp, flag, src_type, kind);
17847d62b00eSchristos       break;
17857d62b00eSchristos 
17867d62b00eSchristos     case CTF_K_ARRAY:
17877d62b00eSchristos       if (ctf_array_info (src_fp, src_type, &src_ar) != 0)
17887d62b00eSchristos 	return (ctf_set_errno (dst_fp, ctf_errno (src_fp)));
17897d62b00eSchristos 
17907d62b00eSchristos       src_ar.ctr_contents =
17917d62b00eSchristos 	ctf_add_type_internal (dst_fp, src_fp, src_ar.ctr_contents,
17927d62b00eSchristos 			       proc_tracking_fp);
17937d62b00eSchristos       src_ar.ctr_index = ctf_add_type_internal (dst_fp, src_fp,
17947d62b00eSchristos 						src_ar.ctr_index,
17957d62b00eSchristos 						proc_tracking_fp);
17967d62b00eSchristos       src_ar.ctr_nelems = src_ar.ctr_nelems;
17977d62b00eSchristos 
17987d62b00eSchristos       if (src_ar.ctr_contents == CTF_ERR || src_ar.ctr_index == CTF_ERR)
17997d62b00eSchristos 	return CTF_ERR;				/* errno is set for us.  */
18007d62b00eSchristos 
18017d62b00eSchristos       if (dst_type != CTF_ERR)
18027d62b00eSchristos 	{
18037d62b00eSchristos 	  if (ctf_array_info (dst_fp, dst_type, &dst_ar) != 0)
18047d62b00eSchristos 	    return CTF_ERR;			/* errno is set for us.  */
18057d62b00eSchristos 
18067d62b00eSchristos 	  if (memcmp (&src_ar, &dst_ar, sizeof (ctf_arinfo_t)))
18077d62b00eSchristos 	    {
18087d62b00eSchristos 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
18097d62b00eSchristos 			    _("conflict for type %s against ID %lx: array info "
18107d62b00eSchristos 			      "differs, old %lx/%lx/%x; new: %lx/%lx/%x"),
18117d62b00eSchristos 			    name, dst_type, src_ar.ctr_contents,
18127d62b00eSchristos 			    src_ar.ctr_index, src_ar.ctr_nelems,
18137d62b00eSchristos 			    dst_ar.ctr_contents, dst_ar.ctr_index,
18147d62b00eSchristos 			    dst_ar.ctr_nelems);
18157d62b00eSchristos 	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
18167d62b00eSchristos 	    }
18177d62b00eSchristos 	}
18187d62b00eSchristos       else
18197d62b00eSchristos 	dst_type = ctf_add_array (dst_fp, flag, &src_ar);
18207d62b00eSchristos       break;
18217d62b00eSchristos 
18227d62b00eSchristos     case CTF_K_FUNCTION:
18237d62b00eSchristos       ctc.ctc_return = ctf_add_type_internal (dst_fp, src_fp,
18247d62b00eSchristos 					      src_tp->ctt_type,
18257d62b00eSchristos 					      proc_tracking_fp);
18267d62b00eSchristos       ctc.ctc_argc = 0;
18277d62b00eSchristos       ctc.ctc_flags = 0;
18287d62b00eSchristos 
18297d62b00eSchristos       if (ctc.ctc_return == CTF_ERR)
18307d62b00eSchristos 	return CTF_ERR;				/* errno is set for us.  */
18317d62b00eSchristos 
18327d62b00eSchristos       dst_type = ctf_add_function (dst_fp, flag, &ctc, NULL);
18337d62b00eSchristos       break;
18347d62b00eSchristos 
18357d62b00eSchristos     case CTF_K_STRUCT:
18367d62b00eSchristos     case CTF_K_UNION:
18377d62b00eSchristos       {
1838*6881a400Schristos 	ctf_next_t *i = NULL;
1839*6881a400Schristos 	ssize_t offset;
1840*6881a400Schristos 	const char *membname;
1841*6881a400Schristos 	ctf_id_t src_membtype;
18427d62b00eSchristos 
18437d62b00eSchristos 	/* Technically to match a struct or union we need to check both
18447d62b00eSchristos 	   ways (src members vs. dst, dst members vs. src) but we make
18457d62b00eSchristos 	   this more optimal by only checking src vs. dst and comparing
18467d62b00eSchristos 	   the total size of the structure (which we must do anyway)
18477d62b00eSchristos 	   which covers the possibility of dst members not in src.
18487d62b00eSchristos 	   This optimization can be defeated for unions, but is so
18497d62b00eSchristos 	   pathological as to render it irrelevant for our purposes.  */
18507d62b00eSchristos 
18517d62b00eSchristos 	if (dst_type != CTF_ERR && kind != CTF_K_FORWARD
18527d62b00eSchristos 	    && dst_kind != CTF_K_FORWARD)
18537d62b00eSchristos 	  {
18547d62b00eSchristos 	    if (ctf_type_size (src_fp, src_type) !=
18557d62b00eSchristos 		ctf_type_size (dst_fp, dst_type))
18567d62b00eSchristos 	      {
18577d62b00eSchristos 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
18587d62b00eSchristos 			      _("conflict for type %s against ID %lx: union "
18597d62b00eSchristos 				"size differs, old %li, new %li"), name,
18607d62b00eSchristos 			      dst_type, (long) ctf_type_size (src_fp, src_type),
18617d62b00eSchristos 			      (long) ctf_type_size (dst_fp, dst_type));
18627d62b00eSchristos 		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
18637d62b00eSchristos 	      }
18647d62b00eSchristos 
18657d62b00eSchristos 	    if (ctf_member_iter (src_fp, src_type, membcmp, &dst))
18667d62b00eSchristos 	      {
18677d62b00eSchristos 		ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
18687d62b00eSchristos 			      _("conflict for type %s against ID %lx: members "
18697d62b00eSchristos 				"differ, see above"), name, dst_type);
18707d62b00eSchristos 		return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
18717d62b00eSchristos 	      }
18727d62b00eSchristos 
18737d62b00eSchristos 	    break;
18747d62b00eSchristos 	  }
18757d62b00eSchristos 
1876*6881a400Schristos 	dst_type = ctf_add_struct_sized (dst_fp, flag, name,
1877*6881a400Schristos 					 ctf_type_size (src_fp, src_type));
18787d62b00eSchristos 	if (dst_type == CTF_ERR)
18797d62b00eSchristos 	  return CTF_ERR;			/* errno is set for us.  */
18807d62b00eSchristos 
18817d62b00eSchristos 	/* Pre-emptively add this struct to the type mapping so that
18827d62b00eSchristos 	   structures that refer to themselves work.  */
18837d62b00eSchristos 	ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type);
18847d62b00eSchristos 
1885*6881a400Schristos 	while ((offset = ctf_member_next (src_fp, src_type, &i, &membname,
1886*6881a400Schristos 					  &src_membtype, 0)) >= 0)
18877d62b00eSchristos 	  {
1888*6881a400Schristos 	    ctf_dict_t *dst = dst_fp;
1889*6881a400Schristos 	    ctf_id_t dst_membtype = ctf_type_mapping (src_fp, src_membtype, &dst);
18907d62b00eSchristos 
1891*6881a400Schristos 	    if (dst_membtype == 0)
18927d62b00eSchristos 	      {
1893*6881a400Schristos 		dst_membtype = ctf_add_type_internal (dst_fp, src_fp,
1894*6881a400Schristos 						      src_membtype,
1895*6881a400Schristos 						      proc_tracking_fp);
1896*6881a400Schristos 		if (dst_membtype == CTF_ERR)
18977d62b00eSchristos 		  {
18987d62b00eSchristos 		    if (ctf_errno (dst_fp) != ECTF_NONREPRESENTABLE)
1899*6881a400Schristos 		      {
1900*6881a400Schristos 			ctf_next_destroy (i);
1901*6881a400Schristos 			break;
19027d62b00eSchristos 		      }
19037d62b00eSchristos 		  }
19047d62b00eSchristos 	      }
19057d62b00eSchristos 
1906*6881a400Schristos 	    if (ctf_add_member_offset (dst_fp, dst_type, membname,
1907*6881a400Schristos 				       dst_membtype, offset) < 0)
1908*6881a400Schristos 	      {
1909*6881a400Schristos 		ctf_next_destroy (i);
1910*6881a400Schristos 		break;
1911*6881a400Schristos 	      }
1912*6881a400Schristos 	  }
1913*6881a400Schristos 	if (ctf_errno (src_fp) != ECTF_NEXT_END)
19147d62b00eSchristos 	  return CTF_ERR;			/* errno is set for us.  */
19157d62b00eSchristos 	break;
19167d62b00eSchristos       }
19177d62b00eSchristos 
19187d62b00eSchristos     case CTF_K_ENUM:
19197d62b00eSchristos       if (dst_type != CTF_ERR && kind != CTF_K_FORWARD
19207d62b00eSchristos 	  && dst_kind != CTF_K_FORWARD)
19217d62b00eSchristos 	{
19227d62b00eSchristos 	  if (ctf_enum_iter (src_fp, src_type, enumcmp, &dst)
19237d62b00eSchristos 	      || ctf_enum_iter (dst_fp, dst_type, enumcmp, &src))
19247d62b00eSchristos 	    {
19257d62b00eSchristos 	      ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
19267d62b00eSchristos 			    _("conflict for enum %s against ID %lx: members "
19277d62b00eSchristos 			      "differ, see above"), name, dst_type);
19287d62b00eSchristos 	      return (ctf_set_errno (dst_fp, ECTF_CONFLICT));
19297d62b00eSchristos 	    }
19307d62b00eSchristos 	}
19317d62b00eSchristos       else
19327d62b00eSchristos 	{
19337d62b00eSchristos 	  dst_type = ctf_add_enum (dst_fp, flag, name);
19347d62b00eSchristos 	  if ((dst.ctb_type = dst_type) == CTF_ERR
19357d62b00eSchristos 	      || ctf_enum_iter (src_fp, src_type, enumadd, &dst))
19367d62b00eSchristos 	    return CTF_ERR;			/* errno is set for us */
19377d62b00eSchristos 	}
19387d62b00eSchristos       break;
19397d62b00eSchristos 
19407d62b00eSchristos     case CTF_K_FORWARD:
19417d62b00eSchristos       if (dst_type == CTF_ERR)
19427d62b00eSchristos 	  dst_type = ctf_add_forward (dst_fp, flag, name, forward_kind);
19437d62b00eSchristos       break;
19447d62b00eSchristos 
19457d62b00eSchristos     case CTF_K_TYPEDEF:
19467d62b00eSchristos       src_type = ctf_type_reference (src_fp, src_type);
19477d62b00eSchristos       src_type = ctf_add_type_internal (dst_fp, src_fp, src_type,
19487d62b00eSchristos 					proc_tracking_fp);
19497d62b00eSchristos 
19507d62b00eSchristos       if (src_type == CTF_ERR)
19517d62b00eSchristos 	return CTF_ERR;				/* errno is set for us.  */
19527d62b00eSchristos 
19537d62b00eSchristos       /* If dst_type is not CTF_ERR at this point, we should check if
19547d62b00eSchristos 	 ctf_type_reference(dst_fp, dst_type) != src_type and if so fail with
19557d62b00eSchristos 	 ECTF_CONFLICT.  However, this causes problems with bitness typedefs
19567d62b00eSchristos 	 that vary based on things like if 32-bit then pid_t is int otherwise
19577d62b00eSchristos 	 long.  We therefore omit this check and assume that if the identically
19587d62b00eSchristos 	 named typedef already exists in dst_fp, it is correct or
19597d62b00eSchristos 	 equivalent.  */
19607d62b00eSchristos 
19617d62b00eSchristos       if (dst_type == CTF_ERR)
19627d62b00eSchristos 	  dst_type = ctf_add_typedef (dst_fp, flag, name, src_type);
19637d62b00eSchristos 
19647d62b00eSchristos       break;
19657d62b00eSchristos 
19667d62b00eSchristos     default:
19677d62b00eSchristos       return (ctf_set_errno (dst_fp, ECTF_CORRUPT));
19687d62b00eSchristos     }
19697d62b00eSchristos 
19707d62b00eSchristos   if (dst_type != CTF_ERR)
19717d62b00eSchristos     ctf_add_type_mapping (src_fp, orig_src_type, dst_fp, dst_type);
19727d62b00eSchristos   return dst_type;
19737d62b00eSchristos }
19747d62b00eSchristos 
19757d62b00eSchristos ctf_id_t
1976*6881a400Schristos ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
19777d62b00eSchristos {
19787d62b00eSchristos   ctf_id_t id;
19797d62b00eSchristos 
19807d62b00eSchristos   if (!src_fp->ctf_add_processing)
19817d62b00eSchristos     src_fp->ctf_add_processing = ctf_dynhash_create (ctf_hash_integer,
19827d62b00eSchristos 						     ctf_hash_eq_integer,
19837d62b00eSchristos 						     NULL, NULL);
19847d62b00eSchristos 
19857d62b00eSchristos   /* We store the hash on the source, because it contains only source type IDs:
19867d62b00eSchristos      but callers will invariably expect errors to appear on the dest.  */
19877d62b00eSchristos   if (!src_fp->ctf_add_processing)
19887d62b00eSchristos     return (ctf_set_errno (dst_fp, ENOMEM));
19897d62b00eSchristos 
19907d62b00eSchristos   id = ctf_add_type_internal (dst_fp, src_fp, src_type, src_fp);
19917d62b00eSchristos   ctf_dynhash_empty (src_fp->ctf_add_processing);
19927d62b00eSchristos 
19937d62b00eSchristos   return id;
19947d62b00eSchristos }
1995