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