10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 22*1222Smws 230Sstevel@tonic-gate /* 24*1222Smws * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 250Sstevel@tonic-gate * Use is subject to license terms. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <sys/sysmacros.h> 310Sstevel@tonic-gate #include <sys/param.h> 320Sstevel@tonic-gate #include <sys/mman.h> 330Sstevel@tonic-gate #include <ctf_impl.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate /* 360Sstevel@tonic-gate * This static string is used as the template for initially populating a 370Sstevel@tonic-gate * dynamic container's string table. We always store \0 in the first byte, 380Sstevel@tonic-gate * and we use the generic string "PARENT" to mark this container's parent 390Sstevel@tonic-gate * if one is associated with the container using ctf_import(). 400Sstevel@tonic-gate */ 410Sstevel@tonic-gate static const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT"; 420Sstevel@tonic-gate 430Sstevel@tonic-gate /* 440Sstevel@tonic-gate * To create an empty CTF container, we just declare a zeroed header and call 450Sstevel@tonic-gate * ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w 460Sstevel@tonic-gate * and initialize the dynamic members. We set dtstrlen to 1 to reserve the 470Sstevel@tonic-gate * first byte of the string table for a \0 byte, and we start assigning type 480Sstevel@tonic-gate * IDs at 1 because type ID 0 is used as a sentinel. 490Sstevel@tonic-gate */ 500Sstevel@tonic-gate ctf_file_t * 510Sstevel@tonic-gate ctf_create(int *errp) 520Sstevel@tonic-gate { 530Sstevel@tonic-gate static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } }; 540Sstevel@tonic-gate 55*1222Smws const ulong_t hashlen = 128; 56*1222Smws ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *)); 570Sstevel@tonic-gate ctf_sect_t cts; 580Sstevel@tonic-gate ctf_file_t *fp; 590Sstevel@tonic-gate 60*1222Smws if (hash == NULL) 61*1222Smws return (ctf_set_open_errno(errp, EAGAIN)); 62*1222Smws 630Sstevel@tonic-gate cts.cts_name = _CTF_SECTION; 640Sstevel@tonic-gate cts.cts_type = SHT_PROGBITS; 650Sstevel@tonic-gate cts.cts_flags = 0; 660Sstevel@tonic-gate cts.cts_data = &hdr; 670Sstevel@tonic-gate cts.cts_size = sizeof (hdr); 680Sstevel@tonic-gate cts.cts_entsize = 1; 690Sstevel@tonic-gate cts.cts_offset = 0; 700Sstevel@tonic-gate 71*1222Smws if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) { 72*1222Smws ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *)); 73*1222Smws return (NULL); 740Sstevel@tonic-gate } 750Sstevel@tonic-gate 76*1222Smws fp->ctf_flags |= LCTF_RDWR; 77*1222Smws fp->ctf_dthashlen = hashlen; 78*1222Smws bzero(hash, hashlen * sizeof (ctf_dtdef_t *)); 79*1222Smws fp->ctf_dthash = hash; 80*1222Smws fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE); 81*1222Smws fp->ctf_dtnextid = 1; 82*1222Smws fp->ctf_dtoldid = 0; 83*1222Smws 840Sstevel@tonic-gate return (fp); 850Sstevel@tonic-gate } 860Sstevel@tonic-gate 870Sstevel@tonic-gate static uchar_t * 880Sstevel@tonic-gate ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 890Sstevel@tonic-gate { 900Sstevel@tonic-gate ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 910Sstevel@tonic-gate ctf_member_t ctm; 920Sstevel@tonic-gate 930Sstevel@tonic-gate for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 940Sstevel@tonic-gate if (dmd->dmd_name) { 950Sstevel@tonic-gate ctm.ctm_name = soff; 960Sstevel@tonic-gate soff += strlen(dmd->dmd_name) + 1; 970Sstevel@tonic-gate } else 980Sstevel@tonic-gate ctm.ctm_name = 0; 990Sstevel@tonic-gate 1000Sstevel@tonic-gate ctm.ctm_type = (ushort_t)dmd->dmd_type; 1010Sstevel@tonic-gate ctm.ctm_offset = (ushort_t)dmd->dmd_offset; 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate bcopy(&ctm, t, sizeof (ctm)); 1040Sstevel@tonic-gate t += sizeof (ctm); 1050Sstevel@tonic-gate } 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate return (t); 1080Sstevel@tonic-gate } 1090Sstevel@tonic-gate 1100Sstevel@tonic-gate static uchar_t * 1110Sstevel@tonic-gate ctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 1120Sstevel@tonic-gate { 1130Sstevel@tonic-gate ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1140Sstevel@tonic-gate ctf_lmember_t ctlm; 1150Sstevel@tonic-gate 1160Sstevel@tonic-gate for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 1170Sstevel@tonic-gate if (dmd->dmd_name) { 1180Sstevel@tonic-gate ctlm.ctlm_name = soff; 1190Sstevel@tonic-gate soff += strlen(dmd->dmd_name) + 1; 1200Sstevel@tonic-gate } else 1210Sstevel@tonic-gate ctlm.ctlm_name = 0; 1220Sstevel@tonic-gate 1230Sstevel@tonic-gate ctlm.ctlm_type = (ushort_t)dmd->dmd_type; 1240Sstevel@tonic-gate ctlm.ctlm_pad = 0; 1250Sstevel@tonic-gate ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); 1260Sstevel@tonic-gate ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); 1270Sstevel@tonic-gate 1280Sstevel@tonic-gate bcopy(&ctlm, t, sizeof (ctlm)); 1290Sstevel@tonic-gate t += sizeof (ctlm); 1300Sstevel@tonic-gate } 1310Sstevel@tonic-gate 1320Sstevel@tonic-gate return (t); 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate static uchar_t * 1360Sstevel@tonic-gate ctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 1370Sstevel@tonic-gate { 1380Sstevel@tonic-gate ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1390Sstevel@tonic-gate ctf_enum_t cte; 1400Sstevel@tonic-gate 1410Sstevel@tonic-gate for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 1420Sstevel@tonic-gate cte.cte_name = soff; 1430Sstevel@tonic-gate cte.cte_value = dmd->dmd_value; 1440Sstevel@tonic-gate soff += strlen(dmd->dmd_name) + 1; 1450Sstevel@tonic-gate bcopy(&cte, t, sizeof (cte)); 1460Sstevel@tonic-gate t += sizeof (cte); 1470Sstevel@tonic-gate } 1480Sstevel@tonic-gate 1490Sstevel@tonic-gate return (t); 1500Sstevel@tonic-gate } 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate static uchar_t * 1530Sstevel@tonic-gate ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) 1540Sstevel@tonic-gate { 1550Sstevel@tonic-gate ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1560Sstevel@tonic-gate size_t len; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 1590Sstevel@tonic-gate if (dmd->dmd_name == NULL) 1600Sstevel@tonic-gate continue; /* skip anonymous members */ 1610Sstevel@tonic-gate len = strlen(dmd->dmd_name) + 1; 1620Sstevel@tonic-gate bcopy(dmd->dmd_name, s, len); 1630Sstevel@tonic-gate s += len; 1640Sstevel@tonic-gate } 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate return (s); 1670Sstevel@tonic-gate } 1680Sstevel@tonic-gate 1690Sstevel@tonic-gate /* 1700Sstevel@tonic-gate * If the specified CTF container is writable and has been modified, reload 1710Sstevel@tonic-gate * this container with the updated type definitions. In order to make this 1720Sstevel@tonic-gate * code and the rest of libctf as simple as possible, we perform updates by 1730Sstevel@tonic-gate * taking the dynamic type definitions and creating an in-memory CTF file 1740Sstevel@tonic-gate * containing the definitions, and then call ctf_bufopen() on it. This not 1750Sstevel@tonic-gate * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest 1760Sstevel@tonic-gate * of the library code with different lookup paths for static and dynamic 1770Sstevel@tonic-gate * type definitions. We are therefore optimizing greatly for lookup over 1780Sstevel@tonic-gate * update, which we assume will be an uncommon operation. We perform one 1790Sstevel@tonic-gate * extra trick here for the benefit of callers and to keep our code simple: 1800Sstevel@tonic-gate * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp 1810Sstevel@tonic-gate * constant for the caller, so after ctf_bufopen() returns, we use bcopy to 1820Sstevel@tonic-gate * swap the interior of the old and new ctf_file_t's, and then free the old. 1830Sstevel@tonic-gate */ 1840Sstevel@tonic-gate int 1850Sstevel@tonic-gate ctf_update(ctf_file_t *fp) 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate ctf_file_t ofp, *nfp; 1880Sstevel@tonic-gate ctf_header_t hdr; 1890Sstevel@tonic-gate ctf_dtdef_t *dtd; 1900Sstevel@tonic-gate ctf_sect_t cts; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate uchar_t *s, *s0, *t; 1930Sstevel@tonic-gate size_t size; 1940Sstevel@tonic-gate void *buf; 1950Sstevel@tonic-gate int err; 1960Sstevel@tonic-gate 1970Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_RDWR)) 1980Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_RDONLY)); 1990Sstevel@tonic-gate 2000Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_DIRTY)) 2010Sstevel@tonic-gate return (0); /* no update required */ 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate /* 2040Sstevel@tonic-gate * Fill in an initial CTF header. We will leave the label, object, 2050Sstevel@tonic-gate * and function sections empty and only output a header, type section, 2060Sstevel@tonic-gate * and string table. The type section begins at a 4-byte aligned 2070Sstevel@tonic-gate * boundary past the CTF header itself (at relative offset zero). 2080Sstevel@tonic-gate */ 2090Sstevel@tonic-gate bzero(&hdr, sizeof (hdr)); 2100Sstevel@tonic-gate hdr.cth_magic = CTF_MAGIC; 2110Sstevel@tonic-gate hdr.cth_version = CTF_VERSION; 2120Sstevel@tonic-gate 2130Sstevel@tonic-gate if (fp->ctf_flags & LCTF_CHILD) 2140Sstevel@tonic-gate hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */ 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate /* 2170Sstevel@tonic-gate * Iterate through the dynamic type definition list and compute the 2180Sstevel@tonic-gate * size of the CTF type section we will need to generate. 2190Sstevel@tonic-gate */ 2200Sstevel@tonic-gate for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs); 2210Sstevel@tonic-gate dtd != NULL; dtd = ctf_list_next(dtd)) { 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 2240Sstevel@tonic-gate uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) 2270Sstevel@tonic-gate size += sizeof (ctf_stype_t); 2280Sstevel@tonic-gate else 2290Sstevel@tonic-gate size += sizeof (ctf_type_t); 2300Sstevel@tonic-gate 2310Sstevel@tonic-gate switch (kind) { 2320Sstevel@tonic-gate case CTF_K_INTEGER: 2330Sstevel@tonic-gate case CTF_K_FLOAT: 2340Sstevel@tonic-gate size += sizeof (uint_t); 2350Sstevel@tonic-gate break; 2360Sstevel@tonic-gate case CTF_K_ARRAY: 2370Sstevel@tonic-gate size += sizeof (ctf_array_t); 2380Sstevel@tonic-gate break; 2390Sstevel@tonic-gate case CTF_K_FUNCTION: 2400Sstevel@tonic-gate size += sizeof (ushort_t) * (vlen + (vlen & 1)); 2410Sstevel@tonic-gate break; 2420Sstevel@tonic-gate case CTF_K_STRUCT: 2430Sstevel@tonic-gate case CTF_K_UNION: 2440Sstevel@tonic-gate if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) 2450Sstevel@tonic-gate size += sizeof (ctf_member_t) * vlen; 2460Sstevel@tonic-gate else 2470Sstevel@tonic-gate size += sizeof (ctf_lmember_t) * vlen; 2480Sstevel@tonic-gate break; 2490Sstevel@tonic-gate case CTF_K_ENUM: 2500Sstevel@tonic-gate size += sizeof (ctf_enum_t) * vlen; 2510Sstevel@tonic-gate break; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate } 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate /* 2560Sstevel@tonic-gate * Fill in the string table offset and size, compute the size of the 2570Sstevel@tonic-gate * entire CTF buffer we need, and then allocate a new buffer and 2580Sstevel@tonic-gate * bcopy the finished header to the start of the buffer. 2590Sstevel@tonic-gate */ 2600Sstevel@tonic-gate hdr.cth_stroff = hdr.cth_typeoff + size; 2610Sstevel@tonic-gate hdr.cth_strlen = fp->ctf_dtstrlen; 2620Sstevel@tonic-gate size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate if ((buf = ctf_data_alloc(size)) == MAP_FAILED) 2650Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate bcopy(&hdr, buf, sizeof (ctf_header_t)); 2680Sstevel@tonic-gate t = (uchar_t *)buf + sizeof (ctf_header_t); 2690Sstevel@tonic-gate s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff; 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE)); 2720Sstevel@tonic-gate s += sizeof (_CTF_STRTAB_TEMPLATE); 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * We now take a final lap through the dynamic type definition list and 2760Sstevel@tonic-gate * copy the appropriate type records and strings to the output buffer. 2770Sstevel@tonic-gate */ 2780Sstevel@tonic-gate for (dtd = ctf_list_next(&fp->ctf_dtdefs); 2790Sstevel@tonic-gate dtd != NULL; dtd = ctf_list_next(dtd)) { 2800Sstevel@tonic-gate 2810Sstevel@tonic-gate uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 2820Sstevel@tonic-gate uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate ctf_array_t cta; 2850Sstevel@tonic-gate uint_t encoding; 2860Sstevel@tonic-gate size_t len; 2870Sstevel@tonic-gate 2880Sstevel@tonic-gate if (dtd->dtd_name != NULL) { 2890Sstevel@tonic-gate dtd->dtd_data.ctt_name = (uint_t)(s - s0); 2900Sstevel@tonic-gate len = strlen(dtd->dtd_name) + 1; 2910Sstevel@tonic-gate bcopy(dtd->dtd_name, s, len); 2920Sstevel@tonic-gate s += len; 2930Sstevel@tonic-gate } else 2940Sstevel@tonic-gate dtd->dtd_data.ctt_name = 0; 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) 2970Sstevel@tonic-gate len = sizeof (ctf_stype_t); 2980Sstevel@tonic-gate else 2990Sstevel@tonic-gate len = sizeof (ctf_type_t); 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate bcopy(&dtd->dtd_data, t, len); 3020Sstevel@tonic-gate t += len; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate switch (kind) { 3050Sstevel@tonic-gate case CTF_K_INTEGER: 3060Sstevel@tonic-gate case CTF_K_FLOAT: 3070Sstevel@tonic-gate if (kind == CTF_K_INTEGER) { 3080Sstevel@tonic-gate encoding = CTF_INT_DATA( 3090Sstevel@tonic-gate dtd->dtd_u.dtu_enc.cte_format, 3100Sstevel@tonic-gate dtd->dtd_u.dtu_enc.cte_offset, 3110Sstevel@tonic-gate dtd->dtd_u.dtu_enc.cte_bits); 3120Sstevel@tonic-gate } else { 3130Sstevel@tonic-gate encoding = CTF_FP_DATA( 3140Sstevel@tonic-gate dtd->dtd_u.dtu_enc.cte_format, 3150Sstevel@tonic-gate dtd->dtd_u.dtu_enc.cte_offset, 3160Sstevel@tonic-gate dtd->dtd_u.dtu_enc.cte_bits); 3170Sstevel@tonic-gate } 3180Sstevel@tonic-gate bcopy(&encoding, t, sizeof (encoding)); 3190Sstevel@tonic-gate t += sizeof (encoding); 3200Sstevel@tonic-gate break; 3210Sstevel@tonic-gate 3220Sstevel@tonic-gate case CTF_K_ARRAY: 3230Sstevel@tonic-gate cta.cta_contents = (ushort_t) 3240Sstevel@tonic-gate dtd->dtd_u.dtu_arr.ctr_contents; 3250Sstevel@tonic-gate cta.cta_index = (ushort_t) 3260Sstevel@tonic-gate dtd->dtd_u.dtu_arr.ctr_index; 3270Sstevel@tonic-gate cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; 3280Sstevel@tonic-gate bcopy(&cta, t, sizeof (cta)); 3290Sstevel@tonic-gate t += sizeof (cta); 3300Sstevel@tonic-gate break; 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate case CTF_K_FUNCTION: { 3330Sstevel@tonic-gate ushort_t *argv = (ushort_t *)(uintptr_t)t; 3340Sstevel@tonic-gate uint_t argc; 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate for (argc = 0; argc < vlen; argc++) 3370Sstevel@tonic-gate *argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc]; 3380Sstevel@tonic-gate 3390Sstevel@tonic-gate if (vlen & 1) 3400Sstevel@tonic-gate *argv++ = 0; /* pad to 4-byte boundary */ 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate t = (uchar_t *)argv; 3430Sstevel@tonic-gate break; 3440Sstevel@tonic-gate } 3450Sstevel@tonic-gate 3460Sstevel@tonic-gate case CTF_K_STRUCT: 3470Sstevel@tonic-gate case CTF_K_UNION: 3480Sstevel@tonic-gate if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) 3490Sstevel@tonic-gate t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t); 3500Sstevel@tonic-gate else 3510Sstevel@tonic-gate t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t); 3520Sstevel@tonic-gate s = ctf_copy_membnames(dtd, s); 3530Sstevel@tonic-gate break; 3540Sstevel@tonic-gate 3550Sstevel@tonic-gate case CTF_K_ENUM: 3560Sstevel@tonic-gate t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t); 3570Sstevel@tonic-gate s = ctf_copy_membnames(dtd, s); 3580Sstevel@tonic-gate break; 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate } 3610Sstevel@tonic-gate 3620Sstevel@tonic-gate /* 3630Sstevel@tonic-gate * Finally, we are ready to ctf_bufopen() the new container. If this 3640Sstevel@tonic-gate * is successful, we then switch nfp and fp and free the old container. 3650Sstevel@tonic-gate */ 3660Sstevel@tonic-gate ctf_data_protect(buf, size); 3670Sstevel@tonic-gate cts.cts_name = _CTF_SECTION; 3680Sstevel@tonic-gate cts.cts_type = SHT_PROGBITS; 3690Sstevel@tonic-gate cts.cts_flags = 0; 3700Sstevel@tonic-gate cts.cts_data = buf; 3710Sstevel@tonic-gate cts.cts_size = size; 3720Sstevel@tonic-gate cts.cts_entsize = 1; 3730Sstevel@tonic-gate cts.cts_offset = 0; 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) { 3760Sstevel@tonic-gate ctf_data_free(buf, size); 3770Sstevel@tonic-gate return (ctf_set_errno(fp, err)); 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate 3800Sstevel@tonic-gate (void) ctf_setmodel(nfp, ctf_getmodel(fp)); 3810Sstevel@tonic-gate (void) ctf_import(nfp, fp->ctf_parent); 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate nfp->ctf_refcnt = fp->ctf_refcnt; 3840Sstevel@tonic-gate nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY; 3850Sstevel@tonic-gate nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */ 386*1222Smws nfp->ctf_dthash = fp->ctf_dthash; 387*1222Smws nfp->ctf_dthashlen = fp->ctf_dthashlen; 3880Sstevel@tonic-gate nfp->ctf_dtdefs = fp->ctf_dtdefs; 3890Sstevel@tonic-gate nfp->ctf_dtstrlen = fp->ctf_dtstrlen; 3900Sstevel@tonic-gate nfp->ctf_dtnextid = fp->ctf_dtnextid; 3910Sstevel@tonic-gate nfp->ctf_dtoldid = fp->ctf_dtnextid - 1; 3920Sstevel@tonic-gate nfp->ctf_specific = fp->ctf_specific; 3930Sstevel@tonic-gate 394*1222Smws fp->ctf_dthash = NULL; 395*1222Smws fp->ctf_dthashlen = 0; 3960Sstevel@tonic-gate bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t)); 397*1222Smws 3980Sstevel@tonic-gate bcopy(fp, &ofp, sizeof (ctf_file_t)); 3990Sstevel@tonic-gate bcopy(nfp, fp, sizeof (ctf_file_t)); 4000Sstevel@tonic-gate bcopy(&ofp, nfp, sizeof (ctf_file_t)); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate /* 4030Sstevel@tonic-gate * Initialize the ctf_lookup_by_name top-level dictionary. We keep an 4040Sstevel@tonic-gate * array of type name prefixes and the corresponding ctf_hash to use. 4050Sstevel@tonic-gate * NOTE: This code must be kept in sync with the code in ctf_bufopen(). 4060Sstevel@tonic-gate */ 4070Sstevel@tonic-gate fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; 4080Sstevel@tonic-gate fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; 4090Sstevel@tonic-gate fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; 4100Sstevel@tonic-gate fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate nfp->ctf_refcnt = 1; /* force nfp to be freed */ 4130Sstevel@tonic-gate ctf_close(nfp); 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate return (0); 4160Sstevel@tonic-gate } 4170Sstevel@tonic-gate 418*1222Smws void 419*1222Smws ctf_dtd_insert(ctf_file_t *fp, ctf_dtdef_t *dtd) 420*1222Smws { 421*1222Smws ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); 422*1222Smws 423*1222Smws dtd->dtd_hash = fp->ctf_dthash[h]; 424*1222Smws fp->ctf_dthash[h] = dtd; 425*1222Smws ctf_list_append(&fp->ctf_dtdefs, dtd); 426*1222Smws } 427*1222Smws 428*1222Smws void 429*1222Smws ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) 430*1222Smws { 431*1222Smws ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); 432*1222Smws ctf_dtdef_t *p, **q = &fp->ctf_dthash[h]; 433*1222Smws ctf_dmdef_t *dmd, *nmd; 434*1222Smws size_t len; 435*1222Smws 436*1222Smws for (p = *q; p != NULL; p = p->dtd_hash) { 437*1222Smws if (p != dtd) 438*1222Smws q = &p->dtd_hash; 439*1222Smws else 440*1222Smws break; 441*1222Smws } 442*1222Smws 443*1222Smws if (p != NULL) 444*1222Smws *q = p->dtd_hash; 445*1222Smws 446*1222Smws switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) { 447*1222Smws case CTF_K_STRUCT: 448*1222Smws case CTF_K_UNION: 449*1222Smws case CTF_K_ENUM: 450*1222Smws for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 451*1222Smws dmd != NULL; dmd = nmd) { 452*1222Smws if (dmd->dmd_name != NULL) { 453*1222Smws len = strlen(dmd->dmd_name) + 1; 454*1222Smws ctf_free(dmd->dmd_name, len); 455*1222Smws fp->ctf_dtstrlen -= len; 456*1222Smws } 457*1222Smws nmd = ctf_list_next(dmd); 458*1222Smws ctf_free(dmd, sizeof (ctf_dmdef_t)); 459*1222Smws } 460*1222Smws break; 461*1222Smws case CTF_K_FUNCTION: 462*1222Smws ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * 463*1222Smws CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); 464*1222Smws break; 465*1222Smws } 466*1222Smws 467*1222Smws if (dtd->dtd_name) { 468*1222Smws len = strlen(dtd->dtd_name) + 1; 469*1222Smws ctf_free(dtd->dtd_name, len); 470*1222Smws fp->ctf_dtstrlen -= len; 471*1222Smws } 472*1222Smws 473*1222Smws ctf_list_delete(&fp->ctf_dtdefs, dtd); 474*1222Smws ctf_free(dtd, sizeof (ctf_dtdef_t)); 475*1222Smws } 476*1222Smws 477*1222Smws ctf_dtdef_t * 478*1222Smws ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) 479*1222Smws { 480*1222Smws ulong_t h = type & (fp->ctf_dthashlen - 1); 481*1222Smws ctf_dtdef_t *dtd; 482*1222Smws 483*1222Smws if (fp->ctf_dthash == NULL) 484*1222Smws return (NULL); 485*1222Smws 486*1222Smws for (dtd = fp->ctf_dthash[h]; dtd != NULL; dtd = dtd->dtd_hash) { 487*1222Smws if (dtd->dtd_type == type) 488*1222Smws break; 489*1222Smws } 490*1222Smws 491*1222Smws return (dtd); 492*1222Smws } 493*1222Smws 4940Sstevel@tonic-gate /* 4950Sstevel@tonic-gate * Discard all of the dynamic type definitions that have been added to the 4960Sstevel@tonic-gate * container since the last call to ctf_update(). We locate such types by 4970Sstevel@tonic-gate * scanning the list and deleting elements that have type IDs greater than 4980Sstevel@tonic-gate * ctf_dtoldid, which is set by ctf_update(), above. 4990Sstevel@tonic-gate */ 5000Sstevel@tonic-gate int 5010Sstevel@tonic-gate ctf_discard(ctf_file_t *fp) 5020Sstevel@tonic-gate { 5030Sstevel@tonic-gate ctf_dtdef_t *dtd, *ntd; 5040Sstevel@tonic-gate 5050Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_RDWR)) 5060Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_RDONLY)); 5070Sstevel@tonic-gate 5080Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_DIRTY)) 5090Sstevel@tonic-gate return (0); /* no update required */ 5100Sstevel@tonic-gate 5110Sstevel@tonic-gate for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { 5120Sstevel@tonic-gate if (dtd->dtd_type <= fp->ctf_dtoldid) 5130Sstevel@tonic-gate continue; /* skip types that have been committed */ 5140Sstevel@tonic-gate 5150Sstevel@tonic-gate ntd = ctf_list_next(dtd); 516*1222Smws ctf_dtd_delete(fp, dtd); 5170Sstevel@tonic-gate } 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate fp->ctf_dtnextid = fp->ctf_dtoldid + 1; 5200Sstevel@tonic-gate fp->ctf_flags &= ~LCTF_DIRTY; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate return (0); 5230Sstevel@tonic-gate } 5240Sstevel@tonic-gate 5250Sstevel@tonic-gate static ctf_id_t 5260Sstevel@tonic-gate ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp) 5270Sstevel@tonic-gate { 5280Sstevel@tonic-gate ctf_dtdef_t *dtd; 5290Sstevel@tonic-gate ctf_id_t type; 5300Sstevel@tonic-gate char *s = NULL; 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT) 5330Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_RDWR)) 5360Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_RDONLY)); 5370Sstevel@tonic-gate 5380Sstevel@tonic-gate if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE) 5390Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_FULL)); 5400Sstevel@tonic-gate 5410Sstevel@tonic-gate if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL) 5420Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 5430Sstevel@tonic-gate 5440Sstevel@tonic-gate if (name != NULL && (s = ctf_strdup(name)) == NULL) { 5450Sstevel@tonic-gate ctf_free(dtd, sizeof (ctf_dtdef_t)); 5460Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate 5490Sstevel@tonic-gate type = fp->ctf_dtnextid++; 5500Sstevel@tonic-gate type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD)); 5510Sstevel@tonic-gate 5520Sstevel@tonic-gate bzero(dtd, sizeof (ctf_dtdef_t)); 5530Sstevel@tonic-gate dtd->dtd_name = s; 5540Sstevel@tonic-gate dtd->dtd_type = type; 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate if (s != NULL) 5570Sstevel@tonic-gate fp->ctf_dtstrlen += strlen(s) + 1; 5580Sstevel@tonic-gate 559*1222Smws ctf_dtd_insert(fp, dtd); 5600Sstevel@tonic-gate fp->ctf_flags |= LCTF_DIRTY; 5610Sstevel@tonic-gate 5620Sstevel@tonic-gate *rp = dtd; 5630Sstevel@tonic-gate return (type); 5640Sstevel@tonic-gate } 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * When encoding integer sizes, we want to convert a byte count in the range 5680Sstevel@tonic-gate * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function 5690Sstevel@tonic-gate * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate static size_t 5720Sstevel@tonic-gate clp2(size_t x) 5730Sstevel@tonic-gate { 5740Sstevel@tonic-gate x--; 5750Sstevel@tonic-gate 5760Sstevel@tonic-gate x |= (x >> 1); 5770Sstevel@tonic-gate x |= (x >> 2); 5780Sstevel@tonic-gate x |= (x >> 4); 5790Sstevel@tonic-gate x |= (x >> 8); 5800Sstevel@tonic-gate x |= (x >> 16); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate return (x + 1); 5830Sstevel@tonic-gate } 5840Sstevel@tonic-gate 5850Sstevel@tonic-gate static ctf_id_t 5860Sstevel@tonic-gate ctf_add_encoded(ctf_file_t *fp, uint_t flag, 5870Sstevel@tonic-gate const char *name, const ctf_encoding_t *ep, uint_t kind) 5880Sstevel@tonic-gate { 5890Sstevel@tonic-gate ctf_dtdef_t *dtd; 5900Sstevel@tonic-gate ctf_id_t type; 5910Sstevel@tonic-gate 5920Sstevel@tonic-gate if (ep == NULL) 5930Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 5940Sstevel@tonic-gate 5950Sstevel@tonic-gate if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 5960Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); 5990Sstevel@tonic-gate dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY); 6000Sstevel@tonic-gate dtd->dtd_u.dtu_enc = *ep; 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate return (type); 6030Sstevel@tonic-gate } 6040Sstevel@tonic-gate 6050Sstevel@tonic-gate static ctf_id_t 6060Sstevel@tonic-gate ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind) 6070Sstevel@tonic-gate { 6080Sstevel@tonic-gate ctf_dtdef_t *dtd; 6090Sstevel@tonic-gate ctf_id_t type; 6100Sstevel@tonic-gate 6110Sstevel@tonic-gate if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) 6120Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 6130Sstevel@tonic-gate 6140Sstevel@tonic-gate if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) 6150Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 6160Sstevel@tonic-gate 6170Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); 6180Sstevel@tonic-gate dtd->dtd_data.ctt_type = (ushort_t)ref; 6190Sstevel@tonic-gate 6200Sstevel@tonic-gate return (type); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate ctf_id_t 6240Sstevel@tonic-gate ctf_add_integer(ctf_file_t *fp, uint_t flag, 6250Sstevel@tonic-gate const char *name, const ctf_encoding_t *ep) 6260Sstevel@tonic-gate { 6270Sstevel@tonic-gate return (ctf_add_encoded(fp, flag, name, ep, CTF_K_INTEGER)); 6280Sstevel@tonic-gate } 6290Sstevel@tonic-gate 6300Sstevel@tonic-gate ctf_id_t 6310Sstevel@tonic-gate ctf_add_float(ctf_file_t *fp, uint_t flag, 6320Sstevel@tonic-gate const char *name, const ctf_encoding_t *ep) 6330Sstevel@tonic-gate { 6340Sstevel@tonic-gate return (ctf_add_encoded(fp, flag, name, ep, CTF_K_FLOAT)); 6350Sstevel@tonic-gate } 6360Sstevel@tonic-gate 6370Sstevel@tonic-gate ctf_id_t 6380Sstevel@tonic-gate ctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 6390Sstevel@tonic-gate { 6400Sstevel@tonic-gate return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER)); 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate ctf_id_t 6440Sstevel@tonic-gate ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) 6450Sstevel@tonic-gate { 6460Sstevel@tonic-gate ctf_dtdef_t *dtd; 6470Sstevel@tonic-gate ctf_id_t type; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if (arp == NULL) 6500Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 6510Sstevel@tonic-gate 6520Sstevel@tonic-gate if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) 6530Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); 6560Sstevel@tonic-gate dtd->dtd_data.ctt_size = 0; 6570Sstevel@tonic-gate dtd->dtd_u.dtu_arr = *arp; 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate return (type); 6600Sstevel@tonic-gate } 6610Sstevel@tonic-gate 6620Sstevel@tonic-gate int 6630Sstevel@tonic-gate ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) 6640Sstevel@tonic-gate { 665*1222Smws ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); 6660Sstevel@tonic-gate 6670Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_RDWR)) 6680Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_RDONLY)); 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) 6710Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_BADID)); 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate fp->ctf_flags |= LCTF_DIRTY; 6740Sstevel@tonic-gate dtd->dtd_u.dtu_arr = *arp; 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate return (0); 6770Sstevel@tonic-gate } 6780Sstevel@tonic-gate 6790Sstevel@tonic-gate ctf_id_t 6800Sstevel@tonic-gate ctf_add_function(ctf_file_t *fp, uint_t flag, 6810Sstevel@tonic-gate const ctf_funcinfo_t *ctc, const ctf_id_t *argv) 6820Sstevel@tonic-gate { 6830Sstevel@tonic-gate ctf_dtdef_t *dtd; 6840Sstevel@tonic-gate ctf_id_t type; 6850Sstevel@tonic-gate uint_t vlen; 6860Sstevel@tonic-gate ctf_id_t *vdat = NULL; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || 6890Sstevel@tonic-gate (ctc->ctc_argc != 0 && argv == NULL)) 6900Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 6910Sstevel@tonic-gate 6920Sstevel@tonic-gate vlen = ctc->ctc_argc; 6930Sstevel@tonic-gate if (ctc->ctc_flags & CTF_FUNC_VARARG) 6940Sstevel@tonic-gate vlen++; /* add trailing zero to indicate varargs (see below) */ 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate if (vlen > CTF_MAX_VLEN) 6970Sstevel@tonic-gate return (ctf_set_errno(fp, EOVERFLOW)); 6980Sstevel@tonic-gate 6990Sstevel@tonic-gate if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) 7000Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 7010Sstevel@tonic-gate 7020Sstevel@tonic-gate if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) { 7030Sstevel@tonic-gate ctf_free(vdat, sizeof (ctf_id_t) * vlen); 7040Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 7050Sstevel@tonic-gate } 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); 7080Sstevel@tonic-gate dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; 7090Sstevel@tonic-gate 7100Sstevel@tonic-gate bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); 7110Sstevel@tonic-gate if (ctc->ctc_flags & CTF_FUNC_VARARG) 7120Sstevel@tonic-gate vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ 7130Sstevel@tonic-gate dtd->dtd_u.dtu_argv = vdat; 7140Sstevel@tonic-gate 7150Sstevel@tonic-gate return (type); 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate ctf_id_t 7190Sstevel@tonic-gate ctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name) 7200Sstevel@tonic-gate { 721*1222Smws ctf_hash_t *hp = &fp->ctf_structs; 722*1222Smws ctf_helem_t *hep = NULL; 7230Sstevel@tonic-gate ctf_dtdef_t *dtd; 7240Sstevel@tonic-gate ctf_id_t type; 7250Sstevel@tonic-gate 726*1222Smws if (name != NULL) 727*1222Smws hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 728*1222Smws 729*1222Smws if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 730*1222Smws dtd = ctf_dtd_lookup(fp, type = hep->h_type); 731*1222Smws else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 7320Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0); 735*1222Smws dtd->dtd_data.ctt_size = 0; 736*1222Smws 7370Sstevel@tonic-gate return (type); 7380Sstevel@tonic-gate } 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate ctf_id_t 7410Sstevel@tonic-gate ctf_add_union(ctf_file_t *fp, uint_t flag, const char *name) 7420Sstevel@tonic-gate { 743*1222Smws ctf_hash_t *hp = &fp->ctf_unions; 744*1222Smws ctf_helem_t *hep = NULL; 7450Sstevel@tonic-gate ctf_dtdef_t *dtd; 7460Sstevel@tonic-gate ctf_id_t type; 7470Sstevel@tonic-gate 748*1222Smws if (name != NULL) 749*1222Smws hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 750*1222Smws 751*1222Smws if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 752*1222Smws dtd = ctf_dtd_lookup(fp, type = hep->h_type); 753*1222Smws else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 7540Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0); 757*1222Smws dtd->dtd_data.ctt_size = 0; 758*1222Smws 7590Sstevel@tonic-gate return (type); 7600Sstevel@tonic-gate } 7610Sstevel@tonic-gate 7620Sstevel@tonic-gate ctf_id_t 7630Sstevel@tonic-gate ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name) 7640Sstevel@tonic-gate { 765*1222Smws ctf_hash_t *hp = &fp->ctf_enums; 766*1222Smws ctf_helem_t *hep = NULL; 7670Sstevel@tonic-gate ctf_dtdef_t *dtd; 7680Sstevel@tonic-gate ctf_id_t type; 7690Sstevel@tonic-gate 770*1222Smws if (name != NULL) 771*1222Smws hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 772*1222Smws 773*1222Smws if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 774*1222Smws dtd = ctf_dtd_lookup(fp, type = hep->h_type); 775*1222Smws else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 7760Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0); 7790Sstevel@tonic-gate dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int; 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate return (type); 7820Sstevel@tonic-gate } 7830Sstevel@tonic-gate 7840Sstevel@tonic-gate ctf_id_t 7850Sstevel@tonic-gate ctf_add_forward(ctf_file_t *fp, uint_t flag, const char *name, uint_t kind) 7860Sstevel@tonic-gate { 787*1222Smws ctf_hash_t *hp; 788*1222Smws ctf_helem_t *hep; 7890Sstevel@tonic-gate ctf_dtdef_t *dtd; 7900Sstevel@tonic-gate ctf_id_t type; 7910Sstevel@tonic-gate 792*1222Smws switch (kind) { 793*1222Smws case CTF_K_STRUCT: 794*1222Smws hp = &fp->ctf_structs; 795*1222Smws break; 796*1222Smws case CTF_K_UNION: 797*1222Smws hp = &fp->ctf_unions; 798*1222Smws break; 799*1222Smws case CTF_K_ENUM: 800*1222Smws hp = &fp->ctf_enums; 801*1222Smws break; 802*1222Smws default: 8030Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_NOTSUE)); 804*1222Smws } 805*1222Smws 806*1222Smws /* 807*1222Smws * If the type is already defined or exists as a forward tag, just 808*1222Smws * return the ctf_id_t of the existing definition. 809*1222Smws */ 810*1222Smws if (name != NULL && (hep = ctf_hash_lookup(hp, 811*1222Smws fp, name, strlen(name))) != NULL) 812*1222Smws return (hep->h_type); 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 8150Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, flag, 0); 818*1222Smws dtd->dtd_data.ctt_type = kind; 819*1222Smws 8200Sstevel@tonic-gate return (type); 8210Sstevel@tonic-gate } 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate ctf_id_t 8240Sstevel@tonic-gate ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) 8250Sstevel@tonic-gate { 8260Sstevel@tonic-gate ctf_dtdef_t *dtd; 8270Sstevel@tonic-gate ctf_id_t type; 8280Sstevel@tonic-gate 8290Sstevel@tonic-gate if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) 8300Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 8310Sstevel@tonic-gate 8320Sstevel@tonic-gate if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 8330Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 8340Sstevel@tonic-gate 8350Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); 8360Sstevel@tonic-gate dtd->dtd_data.ctt_type = (ushort_t)ref; 8370Sstevel@tonic-gate 8380Sstevel@tonic-gate return (type); 8390Sstevel@tonic-gate } 8400Sstevel@tonic-gate 8410Sstevel@tonic-gate ctf_id_t 8420Sstevel@tonic-gate ctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 8430Sstevel@tonic-gate { 8440Sstevel@tonic-gate return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE)); 8450Sstevel@tonic-gate } 8460Sstevel@tonic-gate 8470Sstevel@tonic-gate ctf_id_t 8480Sstevel@tonic-gate ctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 8490Sstevel@tonic-gate { 8500Sstevel@tonic-gate return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST)); 8510Sstevel@tonic-gate } 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate ctf_id_t 8540Sstevel@tonic-gate ctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 8550Sstevel@tonic-gate { 8560Sstevel@tonic-gate return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT)); 8570Sstevel@tonic-gate } 8580Sstevel@tonic-gate 8590Sstevel@tonic-gate int 8600Sstevel@tonic-gate ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value) 8610Sstevel@tonic-gate { 862*1222Smws ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid); 8630Sstevel@tonic-gate ctf_dmdef_t *dmd; 8640Sstevel@tonic-gate 8650Sstevel@tonic-gate uint_t kind, vlen, root; 8660Sstevel@tonic-gate char *s; 8670Sstevel@tonic-gate 8680Sstevel@tonic-gate if (name == NULL) 8690Sstevel@tonic-gate return (ctf_set_errno(fp, EINVAL)); 8700Sstevel@tonic-gate 8710Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_RDWR)) 8720Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_RDONLY)); 8730Sstevel@tonic-gate 8740Sstevel@tonic-gate if (dtd == NULL) 8750Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_BADID)); 8760Sstevel@tonic-gate 8770Sstevel@tonic-gate kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 8780Sstevel@tonic-gate root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); 8790Sstevel@tonic-gate vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 8800Sstevel@tonic-gate 8810Sstevel@tonic-gate if (kind != CTF_K_ENUM) 8820Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_NOTENUM)); 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate if (vlen == CTF_MAX_VLEN) 8850Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_DTFULL)); 8860Sstevel@tonic-gate 8870Sstevel@tonic-gate for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 8880Sstevel@tonic-gate dmd != NULL; dmd = ctf_list_next(dmd)) { 8890Sstevel@tonic-gate if (strcmp(dmd->dmd_name, name) == 0) 8900Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_DUPMEMBER)); 8910Sstevel@tonic-gate } 8920Sstevel@tonic-gate 8930Sstevel@tonic-gate if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 8940Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 8950Sstevel@tonic-gate 8960Sstevel@tonic-gate if ((s = ctf_strdup(name)) == NULL) { 8970Sstevel@tonic-gate ctf_free(dmd, sizeof (ctf_dmdef_t)); 8980Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 8990Sstevel@tonic-gate } 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate dmd->dmd_name = s; 9020Sstevel@tonic-gate dmd->dmd_type = CTF_ERR; 9030Sstevel@tonic-gate dmd->dmd_offset = 0; 9040Sstevel@tonic-gate dmd->dmd_value = value; 9050Sstevel@tonic-gate 9060Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); 9070Sstevel@tonic-gate ctf_list_append(&dtd->dtd_u.dtu_members, dmd); 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate fp->ctf_dtstrlen += strlen(s) + 1; 9100Sstevel@tonic-gate fp->ctf_flags |= LCTF_DIRTY; 9110Sstevel@tonic-gate 9120Sstevel@tonic-gate return (0); 9130Sstevel@tonic-gate } 9140Sstevel@tonic-gate 9150Sstevel@tonic-gate int 9160Sstevel@tonic-gate ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) 9170Sstevel@tonic-gate { 918*1222Smws ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid); 9190Sstevel@tonic-gate ctf_dmdef_t *dmd; 9200Sstevel@tonic-gate 9210Sstevel@tonic-gate ssize_t msize, malign, ssize; 9220Sstevel@tonic-gate uint_t kind, vlen, root; 9230Sstevel@tonic-gate char *s = NULL; 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate if (!(fp->ctf_flags & LCTF_RDWR)) 9260Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_RDONLY)); 9270Sstevel@tonic-gate 9280Sstevel@tonic-gate if (dtd == NULL) 9290Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_BADID)); 9300Sstevel@tonic-gate 9310Sstevel@tonic-gate kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 9320Sstevel@tonic-gate root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); 9330Sstevel@tonic-gate vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 9340Sstevel@tonic-gate 9350Sstevel@tonic-gate if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 9360Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_NOTSOU)); 9370Sstevel@tonic-gate 9380Sstevel@tonic-gate if (vlen == CTF_MAX_VLEN) 9390Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_DTFULL)); 9400Sstevel@tonic-gate 9410Sstevel@tonic-gate if (name != NULL) { 9420Sstevel@tonic-gate for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 9430Sstevel@tonic-gate dmd != NULL; dmd = ctf_list_next(dmd)) { 9440Sstevel@tonic-gate if (dmd->dmd_name != NULL && 9450Sstevel@tonic-gate strcmp(dmd->dmd_name, name) == 0) 9460Sstevel@tonic-gate return (ctf_set_errno(fp, ECTF_DUPMEMBER)); 9470Sstevel@tonic-gate } 9480Sstevel@tonic-gate } 9490Sstevel@tonic-gate 9500Sstevel@tonic-gate if ((msize = ctf_type_size(fp, type)) == CTF_ERR || 9510Sstevel@tonic-gate (malign = ctf_type_align(fp, type)) == CTF_ERR) 9520Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 9530Sstevel@tonic-gate 9540Sstevel@tonic-gate if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 9550Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 9560Sstevel@tonic-gate 9570Sstevel@tonic-gate if (name != NULL && (s = ctf_strdup(name)) == NULL) { 9580Sstevel@tonic-gate ctf_free(dmd, sizeof (ctf_dmdef_t)); 9590Sstevel@tonic-gate return (ctf_set_errno(fp, EAGAIN)); 9600Sstevel@tonic-gate } 9610Sstevel@tonic-gate 9620Sstevel@tonic-gate dmd->dmd_name = s; 9630Sstevel@tonic-gate dmd->dmd_type = type; 9640Sstevel@tonic-gate dmd->dmd_value = -1; 9650Sstevel@tonic-gate 9660Sstevel@tonic-gate if (kind == CTF_K_STRUCT && vlen != 0) { 9670Sstevel@tonic-gate ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members); 9680Sstevel@tonic-gate ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type); 9690Sstevel@tonic-gate size_t off = lmd->dmd_offset; 9700Sstevel@tonic-gate 9710Sstevel@tonic-gate ctf_encoding_t linfo; 9720Sstevel@tonic-gate ssize_t lsize; 9730Sstevel@tonic-gate 9740Sstevel@tonic-gate if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR) 9750Sstevel@tonic-gate off += linfo.cte_bits; 9760Sstevel@tonic-gate else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR) 9770Sstevel@tonic-gate off += lsize * NBBY; 9780Sstevel@tonic-gate 9790Sstevel@tonic-gate /* 9800Sstevel@tonic-gate * Round up the offset of the end of the last member to the 9810Sstevel@tonic-gate * next byte boundary, convert 'off' to bytes, and then round 9820Sstevel@tonic-gate * it up again to the next multiple of the alignment required 9830Sstevel@tonic-gate * by the new member. Finally, convert back to bits and store 9840Sstevel@tonic-gate * the result in dmd_offset. Technically we could do more 9850Sstevel@tonic-gate * efficient packing if the new member is a bit-field, but 9860Sstevel@tonic-gate * we're the "compiler" and ANSI says we can do as we choose. 9870Sstevel@tonic-gate */ 9880Sstevel@tonic-gate off = roundup(off, NBBY) / NBBY; 9890Sstevel@tonic-gate off = roundup(off, MAX(malign, 1)); 9900Sstevel@tonic-gate dmd->dmd_offset = off * NBBY; 9910Sstevel@tonic-gate ssize = off + msize; 9920Sstevel@tonic-gate } else { 9930Sstevel@tonic-gate dmd->dmd_offset = 0; 9940Sstevel@tonic-gate ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL); 9950Sstevel@tonic-gate ssize = MAX(ssize, msize); 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate 9980Sstevel@tonic-gate if (ssize > CTF_MAX_SIZE) { 9990Sstevel@tonic-gate dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; 10000Sstevel@tonic-gate dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize); 10010Sstevel@tonic-gate dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize); 10020Sstevel@tonic-gate } else 10030Sstevel@tonic-gate dtd->dtd_data.ctt_size = (ushort_t)ssize; 10040Sstevel@tonic-gate 10050Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); 10060Sstevel@tonic-gate ctf_list_append(&dtd->dtd_u.dtu_members, dmd); 10070Sstevel@tonic-gate 10080Sstevel@tonic-gate if (s != NULL) 10090Sstevel@tonic-gate fp->ctf_dtstrlen += strlen(s) + 1; 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate fp->ctf_flags |= LCTF_DIRTY; 10120Sstevel@tonic-gate return (0); 10130Sstevel@tonic-gate } 10140Sstevel@tonic-gate 10150Sstevel@tonic-gate static int 10160Sstevel@tonic-gate enumcmp(const char *name, int value, void *arg) 10170Sstevel@tonic-gate { 10180Sstevel@tonic-gate ctf_bundle_t *ctb = arg; 10190Sstevel@tonic-gate int bvalue; 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate return (ctf_enum_value(ctb->ctb_file, ctb->ctb_type, 10220Sstevel@tonic-gate name, &bvalue) == CTF_ERR || value != bvalue); 10230Sstevel@tonic-gate } 10240Sstevel@tonic-gate 10250Sstevel@tonic-gate static int 10260Sstevel@tonic-gate enumadd(const char *name, int value, void *arg) 10270Sstevel@tonic-gate { 10280Sstevel@tonic-gate ctf_bundle_t *ctb = arg; 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate return (ctf_add_enumerator(ctb->ctb_file, ctb->ctb_type, 10310Sstevel@tonic-gate name, value) == CTF_ERR); 10320Sstevel@tonic-gate } 10330Sstevel@tonic-gate 10340Sstevel@tonic-gate /*ARGSUSED*/ 10350Sstevel@tonic-gate static int 10360Sstevel@tonic-gate membcmp(const char *name, ctf_id_t type, ulong_t offset, void *arg) 10370Sstevel@tonic-gate { 10380Sstevel@tonic-gate ctf_bundle_t *ctb = arg; 10390Sstevel@tonic-gate ctf_membinfo_t ctm; 10400Sstevel@tonic-gate 10410Sstevel@tonic-gate return (ctf_member_info(ctb->ctb_file, ctb->ctb_type, 10420Sstevel@tonic-gate name, &ctm) == CTF_ERR || ctm.ctm_offset != offset); 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate static int 10460Sstevel@tonic-gate membadd(const char *name, ctf_id_t type, ulong_t offset, void *arg) 10470Sstevel@tonic-gate { 10480Sstevel@tonic-gate ctf_bundle_t *ctb = arg; 10490Sstevel@tonic-gate ctf_dmdef_t *dmd; 10500Sstevel@tonic-gate char *s = NULL; 10510Sstevel@tonic-gate 10520Sstevel@tonic-gate if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 10530Sstevel@tonic-gate return (ctf_set_errno(ctb->ctb_file, EAGAIN)); 10540Sstevel@tonic-gate 10550Sstevel@tonic-gate if (name != NULL && (s = ctf_strdup(name)) == NULL) { 10560Sstevel@tonic-gate ctf_free(dmd, sizeof (ctf_dmdef_t)); 10570Sstevel@tonic-gate return (ctf_set_errno(ctb->ctb_file, EAGAIN)); 10580Sstevel@tonic-gate } 10590Sstevel@tonic-gate 10600Sstevel@tonic-gate /* 10610Sstevel@tonic-gate * For now, dmd_type is copied as the src_fp's type; it is reset to an 10620Sstevel@tonic-gate * equivalent dst_fp type by a final loop in ctf_add_type(), below. 10630Sstevel@tonic-gate */ 10640Sstevel@tonic-gate dmd->dmd_name = s; 10650Sstevel@tonic-gate dmd->dmd_type = type; 10660Sstevel@tonic-gate dmd->dmd_offset = offset; 10670Sstevel@tonic-gate dmd->dmd_value = -1; 10680Sstevel@tonic-gate 10690Sstevel@tonic-gate ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd); 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate if (s != NULL) 10720Sstevel@tonic-gate ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1; 10730Sstevel@tonic-gate 10740Sstevel@tonic-gate ctb->ctb_file->ctf_flags |= LCTF_DIRTY; 10750Sstevel@tonic-gate return (0); 10760Sstevel@tonic-gate } 10770Sstevel@tonic-gate 10780Sstevel@tonic-gate /* 10790Sstevel@tonic-gate * The ctf_add_type routine is used to copy a type from a source CTF container 10800Sstevel@tonic-gate * to a dynamic destination container. This routine operates recursively by 10810Sstevel@tonic-gate * following the source type's links and embedded member types. If the 10820Sstevel@tonic-gate * destination container already contains a named type which has the same 10830Sstevel@tonic-gate * attributes, then we succeed and return this type but no changes occur. 10840Sstevel@tonic-gate */ 10850Sstevel@tonic-gate ctf_id_t 10860Sstevel@tonic-gate ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) 10870Sstevel@tonic-gate { 10880Sstevel@tonic-gate ctf_id_t dst_type = CTF_ERR; 10890Sstevel@tonic-gate uint_t dst_kind = CTF_K_UNKNOWN; 10900Sstevel@tonic-gate 10910Sstevel@tonic-gate const ctf_type_t *tp; 10920Sstevel@tonic-gate const char *name; 10930Sstevel@tonic-gate uint_t kind, flag, vlen; 10940Sstevel@tonic-gate 10950Sstevel@tonic-gate ctf_bundle_t src, dst; 10960Sstevel@tonic-gate ctf_encoding_t src_en, dst_en; 10970Sstevel@tonic-gate ctf_arinfo_t src_ar, dst_ar; 10980Sstevel@tonic-gate 10990Sstevel@tonic-gate ctf_dtdef_t *dtd; 11000Sstevel@tonic-gate ctf_funcinfo_t ctc; 11010Sstevel@tonic-gate ssize_t size; 11020Sstevel@tonic-gate 11030Sstevel@tonic-gate ctf_hash_t *hp; 11040Sstevel@tonic-gate ctf_helem_t *hep; 11050Sstevel@tonic-gate 11060Sstevel@tonic-gate if (!(dst_fp->ctf_flags & LCTF_RDWR)) 11070Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_RDONLY)); 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate if ((tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL) 11100Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 11110Sstevel@tonic-gate 11120Sstevel@tonic-gate name = ctf_strptr(src_fp, tp->ctt_name); 11130Sstevel@tonic-gate kind = LCTF_INFO_KIND(src_fp, tp->ctt_info); 11140Sstevel@tonic-gate flag = LCTF_INFO_ROOT(src_fp, tp->ctt_info); 11150Sstevel@tonic-gate vlen = LCTF_INFO_VLEN(src_fp, tp->ctt_info); 11160Sstevel@tonic-gate 11170Sstevel@tonic-gate switch (kind) { 11180Sstevel@tonic-gate case CTF_K_STRUCT: 11190Sstevel@tonic-gate hp = &dst_fp->ctf_structs; 11200Sstevel@tonic-gate break; 11210Sstevel@tonic-gate case CTF_K_UNION: 11220Sstevel@tonic-gate hp = &dst_fp->ctf_unions; 11230Sstevel@tonic-gate break; 11240Sstevel@tonic-gate case CTF_K_ENUM: 11250Sstevel@tonic-gate hp = &dst_fp->ctf_enums; 11260Sstevel@tonic-gate break; 11270Sstevel@tonic-gate default: 11280Sstevel@tonic-gate hp = &dst_fp->ctf_names; 11290Sstevel@tonic-gate break; 11300Sstevel@tonic-gate } 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate /* 11330Sstevel@tonic-gate * If the source type has a name and is a root type (visible at the 11340Sstevel@tonic-gate * top-level scope), lookup the name in the destination container and 11350Sstevel@tonic-gate * verify that it is of the same kind before we do anything else. 11360Sstevel@tonic-gate */ 11370Sstevel@tonic-gate if ((flag & CTF_ADD_ROOT) && name[0] != '\0' && 11380Sstevel@tonic-gate (hep = ctf_hash_lookup(hp, dst_fp, name, strlen(name))) != NULL) { 11390Sstevel@tonic-gate dst_type = (ctf_id_t)hep->h_type; 11400Sstevel@tonic-gate dst_kind = ctf_type_kind(dst_fp, dst_type); 11410Sstevel@tonic-gate } 11420Sstevel@tonic-gate 11430Sstevel@tonic-gate /* 11440Sstevel@tonic-gate * If an identically named dst_type exists, fail with ECTF_CONFLICT 11450Sstevel@tonic-gate * unless dst_type is a forward declaration and src_type is a struct, 11460Sstevel@tonic-gate * union, or enum (i.e. the definition of the previous forward decl). 11470Sstevel@tonic-gate */ 11480Sstevel@tonic-gate if (dst_type != CTF_ERR && dst_kind != kind && ( 11490Sstevel@tonic-gate dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM && 11500Sstevel@tonic-gate kind != CTF_K_STRUCT && kind != CTF_K_UNION))) 11510Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate /* 11540Sstevel@tonic-gate * If the non-empty name was not found in the appropriate hash, search 11550Sstevel@tonic-gate * the list of pending dynamic definitions that are not yet committed. 11560Sstevel@tonic-gate * If a matching name and kind are found, assume this is the type that 11570Sstevel@tonic-gate * we are looking for. This is necessary to permit ctf_add_type() to 11580Sstevel@tonic-gate * operate recursively on entities such as a struct that contains a 11590Sstevel@tonic-gate * pointer member that refers to the same struct type. 11600Sstevel@tonic-gate */ 11610Sstevel@tonic-gate if (dst_type == CTF_ERR && name[0] != '\0') { 11620Sstevel@tonic-gate for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL && 11630Sstevel@tonic-gate dtd->dtd_type > dst_fp->ctf_dtoldid; 11640Sstevel@tonic-gate dtd = ctf_list_prev(dtd)) { 11650Sstevel@tonic-gate if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) == kind && 11660Sstevel@tonic-gate dtd->dtd_name != NULL && 11670Sstevel@tonic-gate strcmp(dtd->dtd_name, name) == 0) 11680Sstevel@tonic-gate return (dtd->dtd_type); 11690Sstevel@tonic-gate } 11700Sstevel@tonic-gate } 11710Sstevel@tonic-gate 11720Sstevel@tonic-gate src.ctb_file = src_fp; 11730Sstevel@tonic-gate src.ctb_type = src_type; 11740Sstevel@tonic-gate src.ctb_dtd = NULL; 11750Sstevel@tonic-gate 11760Sstevel@tonic-gate dst.ctb_file = dst_fp; 11770Sstevel@tonic-gate dst.ctb_type = dst_type; 11780Sstevel@tonic-gate dst.ctb_dtd = NULL; 11790Sstevel@tonic-gate 11800Sstevel@tonic-gate /* 11810Sstevel@tonic-gate * Now perform kind-specific processing. If dst_type is CTF_ERR, then 11820Sstevel@tonic-gate * we add a new type with the same properties as src_type to dst_fp. 11830Sstevel@tonic-gate * If dst_type is not CTF_ERR, then we verify that dst_type has the 11840Sstevel@tonic-gate * same attributes as src_type. We recurse for embedded references. 11850Sstevel@tonic-gate */ 11860Sstevel@tonic-gate switch (kind) { 11870Sstevel@tonic-gate case CTF_K_INTEGER: 11880Sstevel@tonic-gate case CTF_K_FLOAT: 11890Sstevel@tonic-gate if (ctf_type_encoding(src_fp, src_type, &src_en) != 0) 11900Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 11910Sstevel@tonic-gate 11920Sstevel@tonic-gate if (dst_type != CTF_ERR) { 11930Sstevel@tonic-gate if (ctf_type_encoding(dst_fp, dst_type, &dst_en) != 0) 11940Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 11950Sstevel@tonic-gate 11960Sstevel@tonic-gate if (bcmp(&src_en, &dst_en, sizeof (ctf_encoding_t))) 11970Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate } else if (kind == CTF_K_INTEGER) { 12000Sstevel@tonic-gate dst_type = ctf_add_integer(dst_fp, flag, name, &src_en); 12010Sstevel@tonic-gate } else 12020Sstevel@tonic-gate dst_type = ctf_add_float(dst_fp, flag, name, &src_en); 12030Sstevel@tonic-gate break; 12040Sstevel@tonic-gate 12050Sstevel@tonic-gate case CTF_K_POINTER: 12060Sstevel@tonic-gate case CTF_K_VOLATILE: 12070Sstevel@tonic-gate case CTF_K_CONST: 12080Sstevel@tonic-gate case CTF_K_RESTRICT: 12090Sstevel@tonic-gate src_type = ctf_type_reference(src_fp, src_type); 12100Sstevel@tonic-gate src_type = ctf_add_type(dst_fp, src_fp, src_type); 12110Sstevel@tonic-gate 12120Sstevel@tonic-gate if (src_type == CTF_ERR) 12130Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 12140Sstevel@tonic-gate 12150Sstevel@tonic-gate dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind); 12160Sstevel@tonic-gate break; 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate case CTF_K_ARRAY: 12190Sstevel@tonic-gate if (ctf_array_info(src_fp, src_type, &src_ar) == CTF_ERR) 12200Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 12210Sstevel@tonic-gate 12220Sstevel@tonic-gate src_ar.ctr_contents = 12230Sstevel@tonic-gate ctf_add_type(dst_fp, src_fp, src_ar.ctr_contents); 12240Sstevel@tonic-gate src_ar.ctr_index = 12250Sstevel@tonic-gate ctf_add_type(dst_fp, src_fp, src_ar.ctr_index); 12260Sstevel@tonic-gate src_ar.ctr_nelems = src_ar.ctr_nelems; 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate if (src_ar.ctr_contents == CTF_ERR || 12290Sstevel@tonic-gate src_ar.ctr_index == CTF_ERR) 12300Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate if (dst_type != CTF_ERR) { 12330Sstevel@tonic-gate if (ctf_array_info(dst_fp, dst_type, &dst_ar) != 0) 12340Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 12350Sstevel@tonic-gate 12360Sstevel@tonic-gate if (bcmp(&src_ar, &dst_ar, sizeof (ctf_arinfo_t))) 12370Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 12380Sstevel@tonic-gate } else 12390Sstevel@tonic-gate dst_type = ctf_add_array(dst_fp, flag, &src_ar); 12400Sstevel@tonic-gate break; 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate case CTF_K_FUNCTION: 12430Sstevel@tonic-gate ctc.ctc_return = ctf_add_type(dst_fp, src_fp, tp->ctt_type); 12440Sstevel@tonic-gate ctc.ctc_argc = 0; 12450Sstevel@tonic-gate ctc.ctc_flags = 0; 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate if (ctc.ctc_return == CTF_ERR) 12480Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL); 12510Sstevel@tonic-gate break; 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate case CTF_K_STRUCT: 12540Sstevel@tonic-gate case CTF_K_UNION: { 12550Sstevel@tonic-gate ctf_dmdef_t *dmd; 12560Sstevel@tonic-gate int errs = 0; 12570Sstevel@tonic-gate 12580Sstevel@tonic-gate /* 12590Sstevel@tonic-gate * Technically to match a struct or union we need to check both 12600Sstevel@tonic-gate * ways (src members vs. dst, dst members vs. src) but we make 12610Sstevel@tonic-gate * this more optimal by only checking src vs. dst and comparing 12620Sstevel@tonic-gate * the total size of the structure (which we must do anyway) 12630Sstevel@tonic-gate * which covers the possibility of dst members not in src. 12640Sstevel@tonic-gate * This optimization can be defeated for unions, but is so 12650Sstevel@tonic-gate * pathological as to render it irrelevant for our purposes. 12660Sstevel@tonic-gate */ 12670Sstevel@tonic-gate if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { 12680Sstevel@tonic-gate if (ctf_type_size(src_fp, src_type) != 12690Sstevel@tonic-gate ctf_type_size(dst_fp, dst_type)) 12700Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 12710Sstevel@tonic-gate 12720Sstevel@tonic-gate if (ctf_member_iter(src_fp, src_type, membcmp, &dst)) 12730Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate break; 12760Sstevel@tonic-gate } 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* 12790Sstevel@tonic-gate * Unlike the other cases, copying structs and unions is done 12800Sstevel@tonic-gate * manually so as to avoid repeated lookups in ctf_add_member 12810Sstevel@tonic-gate * and to ensure the exact same member offsets as in src_type. 12820Sstevel@tonic-gate */ 12830Sstevel@tonic-gate dst_type = ctf_add_generic(dst_fp, flag, name, &dtd); 12840Sstevel@tonic-gate if (dst_type == CTF_ERR) 12850Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate dst.ctb_type = dst_type; 12880Sstevel@tonic-gate dst.ctb_dtd = dtd; 12890Sstevel@tonic-gate 12900Sstevel@tonic-gate if (ctf_member_iter(src_fp, src_type, membadd, &dst) != 0) 12910Sstevel@tonic-gate errs++; /* increment errs and fail at bottom of case */ 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate if ((size = ctf_type_size(src_fp, src_type)) > CTF_MAX_SIZE) { 12940Sstevel@tonic-gate dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; 12950Sstevel@tonic-gate dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size); 12960Sstevel@tonic-gate dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size); 12970Sstevel@tonic-gate } else 12980Sstevel@tonic-gate dtd->dtd_data.ctt_size = (ushort_t)size; 12990Sstevel@tonic-gate 13000Sstevel@tonic-gate dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, vlen); 13010Sstevel@tonic-gate 13020Sstevel@tonic-gate /* 13030Sstevel@tonic-gate * Make a final pass through the members changing each dmd_type 13040Sstevel@tonic-gate * (a src_fp type) to an equivalent type in dst_fp. We pass 13050Sstevel@tonic-gate * through all members, leaving any that fail set to CTF_ERR. 13060Sstevel@tonic-gate */ 13070Sstevel@tonic-gate for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 13080Sstevel@tonic-gate dmd != NULL; dmd = ctf_list_next(dmd)) { 13090Sstevel@tonic-gate if ((dmd->dmd_type = ctf_add_type(dst_fp, src_fp, 13100Sstevel@tonic-gate dmd->dmd_type)) == CTF_ERR) 13110Sstevel@tonic-gate errs++; 13120Sstevel@tonic-gate } 13130Sstevel@tonic-gate 13140Sstevel@tonic-gate if (errs) 13150Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 13160Sstevel@tonic-gate break; 13170Sstevel@tonic-gate } 13180Sstevel@tonic-gate 13190Sstevel@tonic-gate case CTF_K_ENUM: 13200Sstevel@tonic-gate if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { 13210Sstevel@tonic-gate if (ctf_enum_iter(src_fp, src_type, enumcmp, &dst) || 13220Sstevel@tonic-gate ctf_enum_iter(dst_fp, dst_type, enumcmp, &src)) 13230Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 13240Sstevel@tonic-gate } else { 13250Sstevel@tonic-gate dst_type = ctf_add_enum(dst_fp, flag, name); 13260Sstevel@tonic-gate if ((dst.ctb_type = dst_type) == CTF_ERR || 13270Sstevel@tonic-gate ctf_enum_iter(src_fp, src_type, enumadd, &dst)) 13280Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 13290Sstevel@tonic-gate } 13300Sstevel@tonic-gate break; 13310Sstevel@tonic-gate 13320Sstevel@tonic-gate case CTF_K_FORWARD: 13330Sstevel@tonic-gate if (dst_type == CTF_ERR) { 13340Sstevel@tonic-gate dst_type = ctf_add_forward(dst_fp, 13350Sstevel@tonic-gate flag, name, CTF_K_STRUCT); /* assume STRUCT */ 13360Sstevel@tonic-gate } 13370Sstevel@tonic-gate break; 13380Sstevel@tonic-gate 13390Sstevel@tonic-gate case CTF_K_TYPEDEF: 13400Sstevel@tonic-gate src_type = ctf_type_reference(src_fp, src_type); 13410Sstevel@tonic-gate src_type = ctf_add_type(dst_fp, src_fp, src_type); 13420Sstevel@tonic-gate 13430Sstevel@tonic-gate if (src_type == CTF_ERR) 13440Sstevel@tonic-gate return (CTF_ERR); /* errno is set for us */ 13450Sstevel@tonic-gate 13460Sstevel@tonic-gate /* 13470Sstevel@tonic-gate * If dst_type is not CTF_ERR at this point, we should check if 13480Sstevel@tonic-gate * ctf_type_reference(dst_fp, dst_type) != src_type and if so 13490Sstevel@tonic-gate * fail with ECTF_CONFLICT. However, this causes problems with 13500Sstevel@tonic-gate * <sys/types.h> typedefs that vary based on things like if 13510Sstevel@tonic-gate * _ILP32x then pid_t is int otherwise long. We therefore omit 13520Sstevel@tonic-gate * this check and assume that if the identically named typedef 13530Sstevel@tonic-gate * already exists in dst_fp, it is correct or equivalent. 13540Sstevel@tonic-gate */ 13550Sstevel@tonic-gate if (dst_type == CTF_ERR) { 13560Sstevel@tonic-gate dst_type = ctf_add_typedef(dst_fp, flag, 13570Sstevel@tonic-gate name, src_type); 13580Sstevel@tonic-gate } 13590Sstevel@tonic-gate break; 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate default: 13620Sstevel@tonic-gate return (ctf_set_errno(dst_fp, ECTF_CORRUPT)); 13630Sstevel@tonic-gate } 13640Sstevel@tonic-gate 13650Sstevel@tonic-gate return (dst_type); 13660Sstevel@tonic-gate } 1367