1d876124dSJohn Birrell /* 2d876124dSJohn Birrell * CDDL HEADER START 3d876124dSJohn Birrell * 4d876124dSJohn Birrell * The contents of this file are subject to the terms of the 5d876124dSJohn Birrell * Common Development and Distribution License, Version 1.0 only 6d876124dSJohn Birrell * (the "License"). You may not use this file except in compliance 7d876124dSJohn Birrell * with the License. 8d876124dSJohn Birrell * 9d876124dSJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10d876124dSJohn Birrell * or http://www.opensolaris.org/os/licensing. 11d876124dSJohn Birrell * See the License for the specific language governing permissions 12d876124dSJohn Birrell * and limitations under the License. 13d876124dSJohn Birrell * 14d876124dSJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 15d876124dSJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16d876124dSJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 17d876124dSJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 18d876124dSJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 19d876124dSJohn Birrell * 20d876124dSJohn Birrell * CDDL HEADER END 21d876124dSJohn Birrell */ 22d876124dSJohn Birrell 23d876124dSJohn Birrell /* 24d876124dSJohn Birrell * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25d876124dSJohn Birrell * Use is subject to license terms. 26d876124dSJohn Birrell */ 273f0164abSXin LI /* 283f0164abSXin LI * Copyright (c) 2013, Joyent, Inc. All rights reserved. 293f0164abSXin LI */ 30d876124dSJohn Birrell 31d876124dSJohn Birrell #include <sys/sysmacros.h> 32d876124dSJohn Birrell #include <sys/param.h> 33d876124dSJohn Birrell #include <sys/mman.h> 34d876124dSJohn Birrell #include <ctf_impl.h> 353f0164abSXin LI #include <sys/debug.h> 36d876124dSJohn Birrell 37d876124dSJohn Birrell /* 38d876124dSJohn Birrell * This static string is used as the template for initially populating a 39d876124dSJohn Birrell * dynamic container's string table. We always store \0 in the first byte, 40d876124dSJohn Birrell * and we use the generic string "PARENT" to mark this container's parent 41d876124dSJohn Birrell * if one is associated with the container using ctf_import(). 42d876124dSJohn Birrell */ 43d876124dSJohn Birrell static const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT"; 44d876124dSJohn Birrell 45d876124dSJohn Birrell /* 46d876124dSJohn Birrell * To create an empty CTF container, we just declare a zeroed header and call 47d876124dSJohn Birrell * ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w 48d876124dSJohn Birrell * and initialize the dynamic members. We set dtstrlen to 1 to reserve the 49d876124dSJohn Birrell * first byte of the string table for a \0 byte, and we start assigning type 50d876124dSJohn Birrell * IDs at 1 because type ID 0 is used as a sentinel. 51d876124dSJohn Birrell */ 52d876124dSJohn Birrell ctf_file_t * 53d876124dSJohn Birrell ctf_create(int *errp) 54d876124dSJohn Birrell { 55d876124dSJohn Birrell static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } }; 56d876124dSJohn Birrell 57d876124dSJohn Birrell const ulong_t hashlen = 128; 58d876124dSJohn Birrell ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *)); 59d876124dSJohn Birrell ctf_sect_t cts; 60d876124dSJohn Birrell ctf_file_t *fp; 61d876124dSJohn Birrell 62d876124dSJohn Birrell if (hash == NULL) 63d876124dSJohn Birrell return (ctf_set_open_errno(errp, EAGAIN)); 64d876124dSJohn Birrell 65d876124dSJohn Birrell cts.cts_name = _CTF_SECTION; 66d876124dSJohn Birrell cts.cts_type = SHT_PROGBITS; 67d876124dSJohn Birrell cts.cts_flags = 0; 6809d32567SSean Bruno cts.cts_data = (void *)&hdr; 69d876124dSJohn Birrell cts.cts_size = sizeof (hdr); 70d876124dSJohn Birrell cts.cts_entsize = 1; 71d876124dSJohn Birrell cts.cts_offset = 0; 72d876124dSJohn Birrell 73d876124dSJohn Birrell if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) { 74d876124dSJohn Birrell ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *)); 75d876124dSJohn Birrell return (NULL); 76d876124dSJohn Birrell } 77d876124dSJohn Birrell 78d876124dSJohn Birrell fp->ctf_flags |= LCTF_RDWR; 79d876124dSJohn Birrell fp->ctf_dthashlen = hashlen; 80d876124dSJohn Birrell bzero(hash, hashlen * sizeof (ctf_dtdef_t *)); 81d876124dSJohn Birrell fp->ctf_dthash = hash; 82d876124dSJohn Birrell fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE); 83d876124dSJohn Birrell fp->ctf_dtnextid = 1; 84d876124dSJohn Birrell fp->ctf_dtoldid = 0; 85d876124dSJohn Birrell 86d876124dSJohn Birrell return (fp); 87d876124dSJohn Birrell } 88d876124dSJohn Birrell 89d876124dSJohn Birrell static uchar_t * 90d876124dSJohn Birrell ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 91d876124dSJohn Birrell { 92d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 93d876124dSJohn Birrell ctf_member_t ctm; 94d876124dSJohn Birrell 95d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 96d876124dSJohn Birrell if (dmd->dmd_name) { 97d876124dSJohn Birrell ctm.ctm_name = soff; 98d876124dSJohn Birrell soff += strlen(dmd->dmd_name) + 1; 99d876124dSJohn Birrell } else 100d876124dSJohn Birrell ctm.ctm_name = 0; 101d876124dSJohn Birrell 102d876124dSJohn Birrell ctm.ctm_type = (ushort_t)dmd->dmd_type; 103d876124dSJohn Birrell ctm.ctm_offset = (ushort_t)dmd->dmd_offset; 104d876124dSJohn Birrell 105d876124dSJohn Birrell bcopy(&ctm, t, sizeof (ctm)); 106d876124dSJohn Birrell t += sizeof (ctm); 107d876124dSJohn Birrell } 108d876124dSJohn Birrell 109d876124dSJohn Birrell return (t); 110d876124dSJohn Birrell } 111d876124dSJohn Birrell 112d876124dSJohn Birrell static uchar_t * 113d876124dSJohn Birrell ctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 114d876124dSJohn Birrell { 115d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 116d876124dSJohn Birrell ctf_lmember_t ctlm; 117d876124dSJohn Birrell 118d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 119d876124dSJohn Birrell if (dmd->dmd_name) { 120d876124dSJohn Birrell ctlm.ctlm_name = soff; 121d876124dSJohn Birrell soff += strlen(dmd->dmd_name) + 1; 122d876124dSJohn Birrell } else 123d876124dSJohn Birrell ctlm.ctlm_name = 0; 124d876124dSJohn Birrell 125d876124dSJohn Birrell ctlm.ctlm_type = (ushort_t)dmd->dmd_type; 126d876124dSJohn Birrell ctlm.ctlm_pad = 0; 127d876124dSJohn Birrell ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); 128d876124dSJohn Birrell ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); 129d876124dSJohn Birrell 130d876124dSJohn Birrell bcopy(&ctlm, t, sizeof (ctlm)); 131d876124dSJohn Birrell t += sizeof (ctlm); 132d876124dSJohn Birrell } 133d876124dSJohn Birrell 134d876124dSJohn Birrell return (t); 135d876124dSJohn Birrell } 136d876124dSJohn Birrell 137d876124dSJohn Birrell static uchar_t * 138d876124dSJohn Birrell ctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 139d876124dSJohn Birrell { 140d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 141d876124dSJohn Birrell ctf_enum_t cte; 142d876124dSJohn Birrell 143d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 144d876124dSJohn Birrell cte.cte_name = soff; 145d876124dSJohn Birrell cte.cte_value = dmd->dmd_value; 146d876124dSJohn Birrell soff += strlen(dmd->dmd_name) + 1; 147d876124dSJohn Birrell bcopy(&cte, t, sizeof (cte)); 148d876124dSJohn Birrell t += sizeof (cte); 149d876124dSJohn Birrell } 150d876124dSJohn Birrell 151d876124dSJohn Birrell return (t); 152d876124dSJohn Birrell } 153d876124dSJohn Birrell 154d876124dSJohn Birrell static uchar_t * 155d876124dSJohn Birrell ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) 156d876124dSJohn Birrell { 157d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 158d876124dSJohn Birrell size_t len; 159d876124dSJohn Birrell 160d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 161d876124dSJohn Birrell if (dmd->dmd_name == NULL) 162d876124dSJohn Birrell continue; /* skip anonymous members */ 163d876124dSJohn Birrell len = strlen(dmd->dmd_name) + 1; 164d876124dSJohn Birrell bcopy(dmd->dmd_name, s, len); 165d876124dSJohn Birrell s += len; 166d876124dSJohn Birrell } 167d876124dSJohn Birrell 168d876124dSJohn Birrell return (s); 169d876124dSJohn Birrell } 170d876124dSJohn Birrell 171d876124dSJohn Birrell /* 1723f0164abSXin LI * Only types of dyanmic CTF containers contain reference counts. These 1733f0164abSXin LI * containers are marked RD/WR. Because of that we basically make this a no-op 1743f0164abSXin LI * for compatability with non-dynamic CTF sections. This is also a no-op for 1753f0164abSXin LI * types which are not dynamic types. It is the responsibility of the caller to 1763f0164abSXin LI * make sure it is a valid type. We help that caller out on debug builds. 1773f0164abSXin LI * 1783f0164abSXin LI * Note that the reference counts are not maintained for types that are not 1793f0164abSXin LI * within this container. In other words if we have a type in a parent, that 1803f0164abSXin LI * will not have its reference count increased. On the flip side, the parent 1813f0164abSXin LI * will not be allowed to remove dynamic types if it has children. 1823f0164abSXin LI */ 1833f0164abSXin LI static void 1843f0164abSXin LI ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid) 1853f0164abSXin LI { 1863f0164abSXin LI ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); 1873f0164abSXin LI 1883f0164abSXin LI if (dtd == NULL) 1893f0164abSXin LI return; 1903f0164abSXin LI 1913f0164abSXin LI if (!(fp->ctf_flags & LCTF_RDWR)) 1923f0164abSXin LI return; 1933f0164abSXin LI 1943f0164abSXin LI dtd->dtd_ref++; 1953f0164abSXin LI } 1963f0164abSXin LI 1973f0164abSXin LI /* 1983f0164abSXin LI * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the 1993f0164abSXin LI * caller should ensure that this is already a valid type. 2003f0164abSXin LI */ 2013f0164abSXin LI static void 2023f0164abSXin LI ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid) 2033f0164abSXin LI { 2043f0164abSXin LI ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); 2053f0164abSXin LI 2063f0164abSXin LI if (dtd == NULL) 2073f0164abSXin LI return; 2083f0164abSXin LI 2093f0164abSXin LI if (!(fp->ctf_flags & LCTF_RDWR)) 2103f0164abSXin LI return; 2113f0164abSXin LI 2123f0164abSXin LI ASSERT(dtd->dtd_ref >= 1); 2133f0164abSXin LI dtd->dtd_ref--; 2143f0164abSXin LI } 2153f0164abSXin LI 2163f0164abSXin LI /* 217d876124dSJohn Birrell * If the specified CTF container is writable and has been modified, reload 218d876124dSJohn Birrell * this container with the updated type definitions. In order to make this 219d876124dSJohn Birrell * code and the rest of libctf as simple as possible, we perform updates by 220d876124dSJohn Birrell * taking the dynamic type definitions and creating an in-memory CTF file 221d876124dSJohn Birrell * containing the definitions, and then call ctf_bufopen() on it. This not 222d876124dSJohn Birrell * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest 223d876124dSJohn Birrell * of the library code with different lookup paths for static and dynamic 224d876124dSJohn Birrell * type definitions. We are therefore optimizing greatly for lookup over 225d876124dSJohn Birrell * update, which we assume will be an uncommon operation. We perform one 226d876124dSJohn Birrell * extra trick here for the benefit of callers and to keep our code simple: 227d876124dSJohn Birrell * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp 228d876124dSJohn Birrell * constant for the caller, so after ctf_bufopen() returns, we use bcopy to 229d876124dSJohn Birrell * swap the interior of the old and new ctf_file_t's, and then free the old. 2303f0164abSXin LI * 2313f0164abSXin LI * Note that the lists of dynamic types stays around and the resulting container 2323f0164abSXin LI * is still writeable. Furthermore, the reference counts that are on the dtd's 2333f0164abSXin LI * are still valid. 234d876124dSJohn Birrell */ 235d876124dSJohn Birrell int 236d876124dSJohn Birrell ctf_update(ctf_file_t *fp) 237d876124dSJohn Birrell { 238d876124dSJohn Birrell ctf_file_t ofp, *nfp; 239d876124dSJohn Birrell ctf_header_t hdr; 240d876124dSJohn Birrell ctf_dtdef_t *dtd; 241d876124dSJohn Birrell ctf_sect_t cts; 242d876124dSJohn Birrell 243d876124dSJohn Birrell uchar_t *s, *s0, *t; 244d876124dSJohn Birrell size_t size; 245d876124dSJohn Birrell void *buf; 246d876124dSJohn Birrell int err; 247d876124dSJohn Birrell 248d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 249d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 250d876124dSJohn Birrell 251d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_DIRTY)) 252d876124dSJohn Birrell return (0); /* no update required */ 253d876124dSJohn Birrell 254d876124dSJohn Birrell /* 255d876124dSJohn Birrell * Fill in an initial CTF header. We will leave the label, object, 256d876124dSJohn Birrell * and function sections empty and only output a header, type section, 257d876124dSJohn Birrell * and string table. The type section begins at a 4-byte aligned 258d876124dSJohn Birrell * boundary past the CTF header itself (at relative offset zero). 259d876124dSJohn Birrell */ 260d876124dSJohn Birrell bzero(&hdr, sizeof (hdr)); 261d876124dSJohn Birrell hdr.cth_magic = CTF_MAGIC; 262d876124dSJohn Birrell hdr.cth_version = CTF_VERSION; 263d876124dSJohn Birrell 264d876124dSJohn Birrell if (fp->ctf_flags & LCTF_CHILD) 265d876124dSJohn Birrell hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */ 266d876124dSJohn Birrell 267d876124dSJohn Birrell /* 268d876124dSJohn Birrell * Iterate through the dynamic type definition list and compute the 269d876124dSJohn Birrell * size of the CTF type section we will need to generate. 270d876124dSJohn Birrell */ 271d876124dSJohn Birrell for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs); 272d876124dSJohn Birrell dtd != NULL; dtd = ctf_list_next(dtd)) { 273d876124dSJohn Birrell 274d876124dSJohn Birrell uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 275d876124dSJohn Birrell uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 276d876124dSJohn Birrell 277d876124dSJohn Birrell if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) 278d876124dSJohn Birrell size += sizeof (ctf_stype_t); 279d876124dSJohn Birrell else 280d876124dSJohn Birrell size += sizeof (ctf_type_t); 281d876124dSJohn Birrell 282d876124dSJohn Birrell switch (kind) { 283d876124dSJohn Birrell case CTF_K_INTEGER: 284d876124dSJohn Birrell case CTF_K_FLOAT: 285d876124dSJohn Birrell size += sizeof (uint_t); 286d876124dSJohn Birrell break; 287d876124dSJohn Birrell case CTF_K_ARRAY: 288d876124dSJohn Birrell size += sizeof (ctf_array_t); 289d876124dSJohn Birrell break; 290d876124dSJohn Birrell case CTF_K_FUNCTION: 291d876124dSJohn Birrell size += sizeof (ushort_t) * (vlen + (vlen & 1)); 292d876124dSJohn Birrell break; 293d876124dSJohn Birrell case CTF_K_STRUCT: 294d876124dSJohn Birrell case CTF_K_UNION: 295d876124dSJohn Birrell if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) 296d876124dSJohn Birrell size += sizeof (ctf_member_t) * vlen; 297d876124dSJohn Birrell else 298d876124dSJohn Birrell size += sizeof (ctf_lmember_t) * vlen; 299d876124dSJohn Birrell break; 300d876124dSJohn Birrell case CTF_K_ENUM: 301d876124dSJohn Birrell size += sizeof (ctf_enum_t) * vlen; 302d876124dSJohn Birrell break; 303d876124dSJohn Birrell } 304d876124dSJohn Birrell } 305d876124dSJohn Birrell 306d876124dSJohn Birrell /* 307d876124dSJohn Birrell * Fill in the string table offset and size, compute the size of the 308d876124dSJohn Birrell * entire CTF buffer we need, and then allocate a new buffer and 309d876124dSJohn Birrell * bcopy the finished header to the start of the buffer. 310d876124dSJohn Birrell */ 311d876124dSJohn Birrell hdr.cth_stroff = hdr.cth_typeoff + size; 312d876124dSJohn Birrell hdr.cth_strlen = fp->ctf_dtstrlen; 313d876124dSJohn Birrell size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; 314d876124dSJohn Birrell 315d876124dSJohn Birrell if ((buf = ctf_data_alloc(size)) == MAP_FAILED) 316d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 317d876124dSJohn Birrell 318d876124dSJohn Birrell bcopy(&hdr, buf, sizeof (ctf_header_t)); 319d876124dSJohn Birrell t = (uchar_t *)buf + sizeof (ctf_header_t); 320d876124dSJohn Birrell s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff; 321d876124dSJohn Birrell 322d876124dSJohn Birrell bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE)); 323d876124dSJohn Birrell s += sizeof (_CTF_STRTAB_TEMPLATE); 324d876124dSJohn Birrell 325d876124dSJohn Birrell /* 326d876124dSJohn Birrell * We now take a final lap through the dynamic type definition list and 327d876124dSJohn Birrell * copy the appropriate type records and strings to the output buffer. 328d876124dSJohn Birrell */ 329d876124dSJohn Birrell for (dtd = ctf_list_next(&fp->ctf_dtdefs); 330d876124dSJohn Birrell dtd != NULL; dtd = ctf_list_next(dtd)) { 331d876124dSJohn Birrell 332d876124dSJohn Birrell uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 333d876124dSJohn Birrell uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 334d876124dSJohn Birrell 335d876124dSJohn Birrell ctf_array_t cta; 336d876124dSJohn Birrell uint_t encoding; 337d876124dSJohn Birrell size_t len; 338d876124dSJohn Birrell 339d876124dSJohn Birrell if (dtd->dtd_name != NULL) { 340d876124dSJohn Birrell dtd->dtd_data.ctt_name = (uint_t)(s - s0); 341d876124dSJohn Birrell len = strlen(dtd->dtd_name) + 1; 342d876124dSJohn Birrell bcopy(dtd->dtd_name, s, len); 343d876124dSJohn Birrell s += len; 344d876124dSJohn Birrell } else 345d876124dSJohn Birrell dtd->dtd_data.ctt_name = 0; 346d876124dSJohn Birrell 347d876124dSJohn Birrell if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) 348d876124dSJohn Birrell len = sizeof (ctf_stype_t); 349d876124dSJohn Birrell else 350d876124dSJohn Birrell len = sizeof (ctf_type_t); 351d876124dSJohn Birrell 352d876124dSJohn Birrell bcopy(&dtd->dtd_data, t, len); 353d876124dSJohn Birrell t += len; 354d876124dSJohn Birrell 355d876124dSJohn Birrell switch (kind) { 356d876124dSJohn Birrell case CTF_K_INTEGER: 357d876124dSJohn Birrell case CTF_K_FLOAT: 358d876124dSJohn Birrell if (kind == CTF_K_INTEGER) { 359d876124dSJohn Birrell encoding = CTF_INT_DATA( 360d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_format, 361d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_offset, 362d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_bits); 363d876124dSJohn Birrell } else { 364d876124dSJohn Birrell encoding = CTF_FP_DATA( 365d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_format, 366d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_offset, 367d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_bits); 368d876124dSJohn Birrell } 369d876124dSJohn Birrell bcopy(&encoding, t, sizeof (encoding)); 370d876124dSJohn Birrell t += sizeof (encoding); 371d876124dSJohn Birrell break; 372d876124dSJohn Birrell 373d876124dSJohn Birrell case CTF_K_ARRAY: 374d876124dSJohn Birrell cta.cta_contents = (ushort_t) 375d876124dSJohn Birrell dtd->dtd_u.dtu_arr.ctr_contents; 376d876124dSJohn Birrell cta.cta_index = (ushort_t) 377d876124dSJohn Birrell dtd->dtd_u.dtu_arr.ctr_index; 378d876124dSJohn Birrell cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; 379d876124dSJohn Birrell bcopy(&cta, t, sizeof (cta)); 380d876124dSJohn Birrell t += sizeof (cta); 381d876124dSJohn Birrell break; 382d876124dSJohn Birrell 383d876124dSJohn Birrell case CTF_K_FUNCTION: { 384d876124dSJohn Birrell ushort_t *argv = (ushort_t *)(uintptr_t)t; 385d876124dSJohn Birrell uint_t argc; 386d876124dSJohn Birrell 387d876124dSJohn Birrell for (argc = 0; argc < vlen; argc++) 388d876124dSJohn Birrell *argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc]; 389d876124dSJohn Birrell 390d876124dSJohn Birrell if (vlen & 1) 391d876124dSJohn Birrell *argv++ = 0; /* pad to 4-byte boundary */ 392d876124dSJohn Birrell 393d876124dSJohn Birrell t = (uchar_t *)argv; 394d876124dSJohn Birrell break; 395d876124dSJohn Birrell } 396d876124dSJohn Birrell 397d876124dSJohn Birrell case CTF_K_STRUCT: 398d876124dSJohn Birrell case CTF_K_UNION: 399d876124dSJohn Birrell if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) 400d876124dSJohn Birrell t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t); 401d876124dSJohn Birrell else 402d876124dSJohn Birrell t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t); 403d876124dSJohn Birrell s = ctf_copy_membnames(dtd, s); 404d876124dSJohn Birrell break; 405d876124dSJohn Birrell 406d876124dSJohn Birrell case CTF_K_ENUM: 407d876124dSJohn Birrell t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t); 408d876124dSJohn Birrell s = ctf_copy_membnames(dtd, s); 409d876124dSJohn Birrell break; 410d876124dSJohn Birrell } 411d876124dSJohn Birrell } 412d876124dSJohn Birrell 413d876124dSJohn Birrell /* 414d876124dSJohn Birrell * Finally, we are ready to ctf_bufopen() the new container. If this 415d876124dSJohn Birrell * is successful, we then switch nfp and fp and free the old container. 416d876124dSJohn Birrell */ 417d876124dSJohn Birrell ctf_data_protect(buf, size); 418d876124dSJohn Birrell cts.cts_name = _CTF_SECTION; 419d876124dSJohn Birrell cts.cts_type = SHT_PROGBITS; 420d876124dSJohn Birrell cts.cts_flags = 0; 421d876124dSJohn Birrell cts.cts_data = buf; 422d876124dSJohn Birrell cts.cts_size = size; 423d876124dSJohn Birrell cts.cts_entsize = 1; 424d876124dSJohn Birrell cts.cts_offset = 0; 425d876124dSJohn Birrell 426d876124dSJohn Birrell if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) { 427d876124dSJohn Birrell ctf_data_free(buf, size); 428d876124dSJohn Birrell return (ctf_set_errno(fp, err)); 429d876124dSJohn Birrell } 430d876124dSJohn Birrell 431d876124dSJohn Birrell (void) ctf_setmodel(nfp, ctf_getmodel(fp)); 432d876124dSJohn Birrell (void) ctf_import(nfp, fp->ctf_parent); 433d876124dSJohn Birrell 434d876124dSJohn Birrell nfp->ctf_refcnt = fp->ctf_refcnt; 435d876124dSJohn Birrell nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY; 436d876124dSJohn Birrell nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */ 437d876124dSJohn Birrell nfp->ctf_dthash = fp->ctf_dthash; 438d876124dSJohn Birrell nfp->ctf_dthashlen = fp->ctf_dthashlen; 439d876124dSJohn Birrell nfp->ctf_dtdefs = fp->ctf_dtdefs; 440d876124dSJohn Birrell nfp->ctf_dtstrlen = fp->ctf_dtstrlen; 441d876124dSJohn Birrell nfp->ctf_dtnextid = fp->ctf_dtnextid; 442d876124dSJohn Birrell nfp->ctf_dtoldid = fp->ctf_dtnextid - 1; 443d876124dSJohn Birrell nfp->ctf_specific = fp->ctf_specific; 444d876124dSJohn Birrell 445d876124dSJohn Birrell fp->ctf_dthash = NULL; 446d876124dSJohn Birrell fp->ctf_dthashlen = 0; 447d876124dSJohn Birrell bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t)); 448d876124dSJohn Birrell 449d876124dSJohn Birrell bcopy(fp, &ofp, sizeof (ctf_file_t)); 450d876124dSJohn Birrell bcopy(nfp, fp, sizeof (ctf_file_t)); 451d876124dSJohn Birrell bcopy(&ofp, nfp, sizeof (ctf_file_t)); 452d876124dSJohn Birrell 453d876124dSJohn Birrell /* 454d876124dSJohn Birrell * Initialize the ctf_lookup_by_name top-level dictionary. We keep an 455d876124dSJohn Birrell * array of type name prefixes and the corresponding ctf_hash to use. 456d876124dSJohn Birrell * NOTE: This code must be kept in sync with the code in ctf_bufopen(). 457d876124dSJohn Birrell */ 458d876124dSJohn Birrell fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; 459d876124dSJohn Birrell fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; 460d876124dSJohn Birrell fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; 461d876124dSJohn Birrell fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; 462d876124dSJohn Birrell 463d876124dSJohn Birrell nfp->ctf_refcnt = 1; /* force nfp to be freed */ 464d876124dSJohn Birrell ctf_close(nfp); 465d876124dSJohn Birrell 466d876124dSJohn Birrell return (0); 467d876124dSJohn Birrell } 468d876124dSJohn Birrell 469d876124dSJohn Birrell void 470d876124dSJohn Birrell ctf_dtd_insert(ctf_file_t *fp, ctf_dtdef_t *dtd) 471d876124dSJohn Birrell { 472d876124dSJohn Birrell ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); 473d876124dSJohn Birrell 474d876124dSJohn Birrell dtd->dtd_hash = fp->ctf_dthash[h]; 475d876124dSJohn Birrell fp->ctf_dthash[h] = dtd; 476d876124dSJohn Birrell ctf_list_append(&fp->ctf_dtdefs, dtd); 477d876124dSJohn Birrell } 478d876124dSJohn Birrell 479d876124dSJohn Birrell void 480d876124dSJohn Birrell ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) 481d876124dSJohn Birrell { 482d876124dSJohn Birrell ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); 483d876124dSJohn Birrell ctf_dtdef_t *p, **q = &fp->ctf_dthash[h]; 484d876124dSJohn Birrell ctf_dmdef_t *dmd, *nmd; 485d876124dSJohn Birrell size_t len; 4863f0164abSXin LI int kind, i; 487d876124dSJohn Birrell 488d876124dSJohn Birrell for (p = *q; p != NULL; p = p->dtd_hash) { 489d876124dSJohn Birrell if (p != dtd) 490d876124dSJohn Birrell q = &p->dtd_hash; 491d876124dSJohn Birrell else 492d876124dSJohn Birrell break; 493d876124dSJohn Birrell } 494d876124dSJohn Birrell 495d876124dSJohn Birrell if (p != NULL) 496d876124dSJohn Birrell *q = p->dtd_hash; 497d876124dSJohn Birrell 4983f0164abSXin LI kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 4993f0164abSXin LI switch (kind) { 500d876124dSJohn Birrell case CTF_K_STRUCT: 501d876124dSJohn Birrell case CTF_K_UNION: 502d876124dSJohn Birrell case CTF_K_ENUM: 503d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 504d876124dSJohn Birrell dmd != NULL; dmd = nmd) { 505d876124dSJohn Birrell if (dmd->dmd_name != NULL) { 506d876124dSJohn Birrell len = strlen(dmd->dmd_name) + 1; 507d876124dSJohn Birrell ctf_free(dmd->dmd_name, len); 508d876124dSJohn Birrell fp->ctf_dtstrlen -= len; 509d876124dSJohn Birrell } 5103f0164abSXin LI if (kind != CTF_K_ENUM) 5113f0164abSXin LI ctf_ref_dec(fp, dmd->dmd_type); 512d876124dSJohn Birrell nmd = ctf_list_next(dmd); 513d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 514d876124dSJohn Birrell } 515d876124dSJohn Birrell break; 516d876124dSJohn Birrell case CTF_K_FUNCTION: 5173f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_data.ctt_type); 5183f0164abSXin LI for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++) 5193f0164abSXin LI if (dtd->dtd_u.dtu_argv[i] != 0) 5203f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]); 521d876124dSJohn Birrell ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * 522d876124dSJohn Birrell CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); 523d876124dSJohn Birrell break; 5243f0164abSXin LI case CTF_K_ARRAY: 5253f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); 5263f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); 5273f0164abSXin LI break; 5283f0164abSXin LI case CTF_K_TYPEDEF: 5293f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_data.ctt_type); 5303f0164abSXin LI break; 5313f0164abSXin LI case CTF_K_POINTER: 5323f0164abSXin LI case CTF_K_VOLATILE: 5333f0164abSXin LI case CTF_K_CONST: 5343f0164abSXin LI case CTF_K_RESTRICT: 5353f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_data.ctt_type); 5363f0164abSXin LI break; 537d876124dSJohn Birrell } 538d876124dSJohn Birrell 539d876124dSJohn Birrell if (dtd->dtd_name) { 540d876124dSJohn Birrell len = strlen(dtd->dtd_name) + 1; 541d876124dSJohn Birrell ctf_free(dtd->dtd_name, len); 542d876124dSJohn Birrell fp->ctf_dtstrlen -= len; 543d876124dSJohn Birrell } 544d876124dSJohn Birrell 545d876124dSJohn Birrell ctf_list_delete(&fp->ctf_dtdefs, dtd); 546d876124dSJohn Birrell ctf_free(dtd, sizeof (ctf_dtdef_t)); 547d876124dSJohn Birrell } 548d876124dSJohn Birrell 549d876124dSJohn Birrell ctf_dtdef_t * 550d876124dSJohn Birrell ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) 551d876124dSJohn Birrell { 552d876124dSJohn Birrell ulong_t h = type & (fp->ctf_dthashlen - 1); 553d876124dSJohn Birrell ctf_dtdef_t *dtd; 554d876124dSJohn Birrell 555d876124dSJohn Birrell if (fp->ctf_dthash == NULL) 556d876124dSJohn Birrell return (NULL); 557d876124dSJohn Birrell 558d876124dSJohn Birrell for (dtd = fp->ctf_dthash[h]; dtd != NULL; dtd = dtd->dtd_hash) { 559d876124dSJohn Birrell if (dtd->dtd_type == type) 560d876124dSJohn Birrell break; 561d876124dSJohn Birrell } 562d876124dSJohn Birrell 563d876124dSJohn Birrell return (dtd); 564d876124dSJohn Birrell } 565d876124dSJohn Birrell 566d876124dSJohn Birrell /* 567d876124dSJohn Birrell * Discard all of the dynamic type definitions that have been added to the 568d876124dSJohn Birrell * container since the last call to ctf_update(). We locate such types by 569d876124dSJohn Birrell * scanning the list and deleting elements that have type IDs greater than 5703f0164abSXin LI * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly 5713f0164abSXin LI * with our reference counting schemes, we must delete the dynamic list in 5723f0164abSXin LI * reverse. 573d876124dSJohn Birrell */ 574d876124dSJohn Birrell int 575d876124dSJohn Birrell ctf_discard(ctf_file_t *fp) 576d876124dSJohn Birrell { 577d876124dSJohn Birrell ctf_dtdef_t *dtd, *ntd; 578d876124dSJohn Birrell 579d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 580d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 581d876124dSJohn Birrell 582d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_DIRTY)) 583d876124dSJohn Birrell return (0); /* no update required */ 584d876124dSJohn Birrell 5853f0164abSXin LI for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { 586ba8d15d3SMark Johnston ntd = ctf_list_prev(dtd); 587b0ee9129SMark Johnston if (CTF_TYPE_TO_INDEX(dtd->dtd_type) <= fp->ctf_dtoldid) 588d876124dSJohn Birrell continue; /* skip types that have been committed */ 589d876124dSJohn Birrell 590d876124dSJohn Birrell ctf_dtd_delete(fp, dtd); 591d876124dSJohn Birrell } 592d876124dSJohn Birrell 593d876124dSJohn Birrell fp->ctf_dtnextid = fp->ctf_dtoldid + 1; 594d876124dSJohn Birrell fp->ctf_flags &= ~LCTF_DIRTY; 595d876124dSJohn Birrell 596d876124dSJohn Birrell return (0); 597d876124dSJohn Birrell } 598d876124dSJohn Birrell 599d876124dSJohn Birrell static ctf_id_t 600d876124dSJohn Birrell ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp) 601d876124dSJohn Birrell { 602d876124dSJohn Birrell ctf_dtdef_t *dtd; 603d876124dSJohn Birrell ctf_id_t type; 604d876124dSJohn Birrell char *s = NULL; 605d876124dSJohn Birrell 606d876124dSJohn Birrell if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT) 607d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 608d876124dSJohn Birrell 609d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 610d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 611d876124dSJohn Birrell 612d876124dSJohn Birrell if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE) 613d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_FULL)); 614d876124dSJohn Birrell 615d876124dSJohn Birrell if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL) 616d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 617d876124dSJohn Birrell 618d876124dSJohn Birrell if (name != NULL && (s = ctf_strdup(name)) == NULL) { 619d876124dSJohn Birrell ctf_free(dtd, sizeof (ctf_dtdef_t)); 620d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 621d876124dSJohn Birrell } 622d876124dSJohn Birrell 623d876124dSJohn Birrell type = fp->ctf_dtnextid++; 624d876124dSJohn Birrell type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD)); 625d876124dSJohn Birrell 626d876124dSJohn Birrell bzero(dtd, sizeof (ctf_dtdef_t)); 627d876124dSJohn Birrell dtd->dtd_name = s; 628d876124dSJohn Birrell dtd->dtd_type = type; 629d876124dSJohn Birrell 630d876124dSJohn Birrell if (s != NULL) 631d876124dSJohn Birrell fp->ctf_dtstrlen += strlen(s) + 1; 632d876124dSJohn Birrell 633d876124dSJohn Birrell ctf_dtd_insert(fp, dtd); 634d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 635d876124dSJohn Birrell 636d876124dSJohn Birrell *rp = dtd; 637d876124dSJohn Birrell return (type); 638d876124dSJohn Birrell } 639d876124dSJohn Birrell 640d876124dSJohn Birrell /* 641d876124dSJohn Birrell * When encoding integer sizes, we want to convert a byte count in the range 642d876124dSJohn Birrell * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function 643d876124dSJohn Birrell * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. 644d876124dSJohn Birrell */ 645d876124dSJohn Birrell static size_t 646d876124dSJohn Birrell clp2(size_t x) 647d876124dSJohn Birrell { 648d876124dSJohn Birrell x--; 649d876124dSJohn Birrell 650d876124dSJohn Birrell x |= (x >> 1); 651d876124dSJohn Birrell x |= (x >> 2); 652d876124dSJohn Birrell x |= (x >> 4); 653d876124dSJohn Birrell x |= (x >> 8); 654d876124dSJohn Birrell x |= (x >> 16); 655d876124dSJohn Birrell 656d876124dSJohn Birrell return (x + 1); 657d876124dSJohn Birrell } 658d876124dSJohn Birrell 659d876124dSJohn Birrell static ctf_id_t 660d876124dSJohn Birrell ctf_add_encoded(ctf_file_t *fp, uint_t flag, 661d876124dSJohn Birrell const char *name, const ctf_encoding_t *ep, uint_t kind) 662d876124dSJohn Birrell { 663d876124dSJohn Birrell ctf_dtdef_t *dtd; 664d876124dSJohn Birrell ctf_id_t type; 665d876124dSJohn Birrell 666d876124dSJohn Birrell if (ep == NULL) 667d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 668d876124dSJohn Birrell 669d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 670d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 671d876124dSJohn Birrell 672d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); 673d876124dSJohn Birrell dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY); 674d876124dSJohn Birrell dtd->dtd_u.dtu_enc = *ep; 675d876124dSJohn Birrell 676d876124dSJohn Birrell return (type); 677d876124dSJohn Birrell } 678d876124dSJohn Birrell 679d876124dSJohn Birrell static ctf_id_t 680d876124dSJohn Birrell ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind) 681d876124dSJohn Birrell { 682d876124dSJohn Birrell ctf_dtdef_t *dtd; 683d876124dSJohn Birrell ctf_id_t type; 684d876124dSJohn Birrell 685d876124dSJohn Birrell if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) 686d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 687d876124dSJohn Birrell 688d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) 689d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 690d876124dSJohn Birrell 6913f0164abSXin LI ctf_ref_inc(fp, ref); 6923f0164abSXin LI 693d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); 694d876124dSJohn Birrell dtd->dtd_data.ctt_type = (ushort_t)ref; 695d876124dSJohn Birrell 696d876124dSJohn Birrell return (type); 697d876124dSJohn Birrell } 698d876124dSJohn Birrell 699d876124dSJohn Birrell ctf_id_t 700d876124dSJohn Birrell ctf_add_integer(ctf_file_t *fp, uint_t flag, 701d876124dSJohn Birrell const char *name, const ctf_encoding_t *ep) 702d876124dSJohn Birrell { 703d876124dSJohn Birrell return (ctf_add_encoded(fp, flag, name, ep, CTF_K_INTEGER)); 704d876124dSJohn Birrell } 705d876124dSJohn Birrell 706d876124dSJohn Birrell ctf_id_t 707d876124dSJohn Birrell ctf_add_float(ctf_file_t *fp, uint_t flag, 708d876124dSJohn Birrell const char *name, const ctf_encoding_t *ep) 709d876124dSJohn Birrell { 710d876124dSJohn Birrell return (ctf_add_encoded(fp, flag, name, ep, CTF_K_FLOAT)); 711d876124dSJohn Birrell } 712d876124dSJohn Birrell 713d876124dSJohn Birrell ctf_id_t 714d876124dSJohn Birrell ctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 715d876124dSJohn Birrell { 716d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER)); 717d876124dSJohn Birrell } 718d876124dSJohn Birrell 719d876124dSJohn Birrell ctf_id_t 720d876124dSJohn Birrell ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) 721d876124dSJohn Birrell { 722d876124dSJohn Birrell ctf_dtdef_t *dtd; 723d876124dSJohn Birrell ctf_id_t type; 7243f0164abSXin LI ctf_file_t *fpd; 725d876124dSJohn Birrell 726d876124dSJohn Birrell if (arp == NULL) 727d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 728d876124dSJohn Birrell 7293f0164abSXin LI fpd = fp; 7303f0164abSXin LI if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && 7313f0164abSXin LI ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) 7323f0164abSXin LI return (ctf_set_errno(fp, ECTF_BADID)); 7333f0164abSXin LI 7343f0164abSXin LI fpd = fp; 7353f0164abSXin LI if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && 7363f0164abSXin LI ctf_dtd_lookup(fp, arp->ctr_index) == NULL) 7373f0164abSXin LI return (ctf_set_errno(fp, ECTF_BADID)); 7383f0164abSXin LI 739d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) 740d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 741d876124dSJohn Birrell 742d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); 743d876124dSJohn Birrell dtd->dtd_data.ctt_size = 0; 744d876124dSJohn Birrell dtd->dtd_u.dtu_arr = *arp; 7453f0164abSXin LI ctf_ref_inc(fp, arp->ctr_contents); 7463f0164abSXin LI ctf_ref_inc(fp, arp->ctr_index); 747d876124dSJohn Birrell 748d876124dSJohn Birrell return (type); 749d876124dSJohn Birrell } 750d876124dSJohn Birrell 751d876124dSJohn Birrell int 752d876124dSJohn Birrell ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) 753d876124dSJohn Birrell { 7543f0164abSXin LI ctf_file_t *fpd; 755d876124dSJohn Birrell ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); 756d876124dSJohn Birrell 757d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 758d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 759d876124dSJohn Birrell 760d876124dSJohn Birrell if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) 761d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_BADID)); 762d876124dSJohn Birrell 7633f0164abSXin LI fpd = fp; 7643f0164abSXin LI if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && 7653f0164abSXin LI ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) 7663f0164abSXin LI return (ctf_set_errno(fp, ECTF_BADID)); 7673f0164abSXin LI 7683f0164abSXin LI fpd = fp; 7693f0164abSXin LI if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && 7703f0164abSXin LI ctf_dtd_lookup(fp, arp->ctr_index) == NULL) 7713f0164abSXin LI return (ctf_set_errno(fp, ECTF_BADID)); 7723f0164abSXin LI 7733f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); 7743f0164abSXin LI ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); 775d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 776d876124dSJohn Birrell dtd->dtd_u.dtu_arr = *arp; 7773f0164abSXin LI ctf_ref_inc(fp, arp->ctr_contents); 7783f0164abSXin LI ctf_ref_inc(fp, arp->ctr_index); 779d876124dSJohn Birrell 780d876124dSJohn Birrell return (0); 781d876124dSJohn Birrell } 782d876124dSJohn Birrell 783d876124dSJohn Birrell ctf_id_t 784d876124dSJohn Birrell ctf_add_function(ctf_file_t *fp, uint_t flag, 785d876124dSJohn Birrell const ctf_funcinfo_t *ctc, const ctf_id_t *argv) 786d876124dSJohn Birrell { 787d876124dSJohn Birrell ctf_dtdef_t *dtd; 788d876124dSJohn Birrell ctf_id_t type; 789d876124dSJohn Birrell uint_t vlen; 7903f0164abSXin LI int i; 791d876124dSJohn Birrell ctf_id_t *vdat = NULL; 7923f0164abSXin LI ctf_file_t *fpd; 793d876124dSJohn Birrell 794d876124dSJohn Birrell if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || 795d876124dSJohn Birrell (ctc->ctc_argc != 0 && argv == NULL)) 796d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 797d876124dSJohn Birrell 798d876124dSJohn Birrell vlen = ctc->ctc_argc; 799d876124dSJohn Birrell if (ctc->ctc_flags & CTF_FUNC_VARARG) 800d876124dSJohn Birrell vlen++; /* add trailing zero to indicate varargs (see below) */ 801d876124dSJohn Birrell 802d876124dSJohn Birrell if (vlen > CTF_MAX_VLEN) 803d876124dSJohn Birrell return (ctf_set_errno(fp, EOVERFLOW)); 804d876124dSJohn Birrell 8053f0164abSXin LI fpd = fp; 8063f0164abSXin LI if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL && 8073f0164abSXin LI ctf_dtd_lookup(fp, ctc->ctc_return) == NULL) 8083f0164abSXin LI return (ctf_set_errno(fp, ECTF_BADID)); 8093f0164abSXin LI 8103f0164abSXin LI for (i = 0; i < ctc->ctc_argc; i++) { 8113f0164abSXin LI fpd = fp; 8123f0164abSXin LI if (ctf_lookup_by_id(&fpd, argv[i]) == NULL && 8133f0164abSXin LI ctf_dtd_lookup(fp, argv[i]) == NULL) 8143f0164abSXin LI return (ctf_set_errno(fp, ECTF_BADID)); 8153f0164abSXin LI } 8163f0164abSXin LI 817d876124dSJohn Birrell if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) 818d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 819d876124dSJohn Birrell 820d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) { 821d876124dSJohn Birrell ctf_free(vdat, sizeof (ctf_id_t) * vlen); 822d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 823d876124dSJohn Birrell } 824d876124dSJohn Birrell 825d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); 826d876124dSJohn Birrell dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; 827d876124dSJohn Birrell 8283f0164abSXin LI ctf_ref_inc(fp, ctc->ctc_return); 8293f0164abSXin LI for (i = 0; i < ctc->ctc_argc; i++) 8303f0164abSXin LI ctf_ref_inc(fp, argv[i]); 8313f0164abSXin LI 832d876124dSJohn Birrell bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); 833d876124dSJohn Birrell if (ctc->ctc_flags & CTF_FUNC_VARARG) 834d876124dSJohn Birrell vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ 835d876124dSJohn Birrell dtd->dtd_u.dtu_argv = vdat; 836d876124dSJohn Birrell 837d876124dSJohn Birrell return (type); 838d876124dSJohn Birrell } 839d876124dSJohn Birrell 840d876124dSJohn Birrell ctf_id_t 841d876124dSJohn Birrell ctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name) 842d876124dSJohn Birrell { 843d876124dSJohn Birrell ctf_hash_t *hp = &fp->ctf_structs; 844d876124dSJohn Birrell ctf_helem_t *hep = NULL; 845d876124dSJohn Birrell ctf_dtdef_t *dtd; 846d876124dSJohn Birrell ctf_id_t type; 847d876124dSJohn Birrell 848d876124dSJohn Birrell if (name != NULL) 849d876124dSJohn Birrell hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 850d876124dSJohn Birrell 851d876124dSJohn Birrell if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 852d876124dSJohn Birrell dtd = ctf_dtd_lookup(fp, type = hep->h_type); 853d876124dSJohn Birrell else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 854d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 855d876124dSJohn Birrell 856d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0); 857d876124dSJohn Birrell dtd->dtd_data.ctt_size = 0; 858d876124dSJohn Birrell 859d876124dSJohn Birrell return (type); 860d876124dSJohn Birrell } 861d876124dSJohn Birrell 862d876124dSJohn Birrell ctf_id_t 863d876124dSJohn Birrell ctf_add_union(ctf_file_t *fp, uint_t flag, const char *name) 864d876124dSJohn Birrell { 865d876124dSJohn Birrell ctf_hash_t *hp = &fp->ctf_unions; 866d876124dSJohn Birrell ctf_helem_t *hep = NULL; 867d876124dSJohn Birrell ctf_dtdef_t *dtd; 868d876124dSJohn Birrell ctf_id_t type; 869d876124dSJohn Birrell 870d876124dSJohn Birrell if (name != NULL) 871d876124dSJohn Birrell hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 872d876124dSJohn Birrell 873d876124dSJohn Birrell if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 874d876124dSJohn Birrell dtd = ctf_dtd_lookup(fp, type = hep->h_type); 875d876124dSJohn Birrell else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 876d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 877d876124dSJohn Birrell 878d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0); 879d876124dSJohn Birrell dtd->dtd_data.ctt_size = 0; 880d876124dSJohn Birrell 881d876124dSJohn Birrell return (type); 882d876124dSJohn Birrell } 883d876124dSJohn Birrell 884d876124dSJohn Birrell ctf_id_t 885d876124dSJohn Birrell ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name) 886d876124dSJohn Birrell { 887d876124dSJohn Birrell ctf_hash_t *hp = &fp->ctf_enums; 888d876124dSJohn Birrell ctf_helem_t *hep = NULL; 889d876124dSJohn Birrell ctf_dtdef_t *dtd; 890d876124dSJohn Birrell ctf_id_t type; 891d876124dSJohn Birrell 892d876124dSJohn Birrell if (name != NULL) 893d876124dSJohn Birrell hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 894d876124dSJohn Birrell 895d876124dSJohn Birrell if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 896d876124dSJohn Birrell dtd = ctf_dtd_lookup(fp, type = hep->h_type); 897d876124dSJohn Birrell else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 898d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 899d876124dSJohn Birrell 900d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0); 901d876124dSJohn Birrell dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int; 902d876124dSJohn Birrell 903d876124dSJohn Birrell return (type); 904d876124dSJohn Birrell } 905d876124dSJohn Birrell 906d876124dSJohn Birrell ctf_id_t 907d876124dSJohn Birrell ctf_add_forward(ctf_file_t *fp, uint_t flag, const char *name, uint_t kind) 908d876124dSJohn Birrell { 909d876124dSJohn Birrell ctf_hash_t *hp; 910d876124dSJohn Birrell ctf_helem_t *hep; 911d876124dSJohn Birrell ctf_dtdef_t *dtd; 912d876124dSJohn Birrell ctf_id_t type; 913d876124dSJohn Birrell 914d876124dSJohn Birrell switch (kind) { 915d876124dSJohn Birrell case CTF_K_STRUCT: 916d876124dSJohn Birrell hp = &fp->ctf_structs; 917d876124dSJohn Birrell break; 918d876124dSJohn Birrell case CTF_K_UNION: 919d876124dSJohn Birrell hp = &fp->ctf_unions; 920d876124dSJohn Birrell break; 921d876124dSJohn Birrell case CTF_K_ENUM: 922d876124dSJohn Birrell hp = &fp->ctf_enums; 923d876124dSJohn Birrell break; 924d876124dSJohn Birrell default: 925d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_NOTSUE)); 926d876124dSJohn Birrell } 927d876124dSJohn Birrell 928d876124dSJohn Birrell /* 929d876124dSJohn Birrell * If the type is already defined or exists as a forward tag, just 930d876124dSJohn Birrell * return the ctf_id_t of the existing definition. 931d876124dSJohn Birrell */ 932d876124dSJohn Birrell if (name != NULL && (hep = ctf_hash_lookup(hp, 933d876124dSJohn Birrell fp, name, strlen(name))) != NULL) 934d876124dSJohn Birrell return (hep->h_type); 935d876124dSJohn Birrell 936d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 937d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 938d876124dSJohn Birrell 939d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, flag, 0); 940d876124dSJohn Birrell dtd->dtd_data.ctt_type = kind; 941d876124dSJohn Birrell 942d876124dSJohn Birrell return (type); 943d876124dSJohn Birrell } 944d876124dSJohn Birrell 945d876124dSJohn Birrell ctf_id_t 946d876124dSJohn Birrell ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) 947d876124dSJohn Birrell { 948d876124dSJohn Birrell ctf_dtdef_t *dtd; 949d876124dSJohn Birrell ctf_id_t type; 9503f0164abSXin LI ctf_file_t *fpd; 951d876124dSJohn Birrell 9523f0164abSXin LI fpd = fp; 9533f0164abSXin LI if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL && 9543f0164abSXin LI ctf_dtd_lookup(fp, ref) == NULL)) 955d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 956d876124dSJohn Birrell 957d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 958d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 959d876124dSJohn Birrell 960d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); 961d876124dSJohn Birrell dtd->dtd_data.ctt_type = (ushort_t)ref; 9623f0164abSXin LI ctf_ref_inc(fp, ref); 963d876124dSJohn Birrell 964d876124dSJohn Birrell return (type); 965d876124dSJohn Birrell } 966d876124dSJohn Birrell 967d876124dSJohn Birrell ctf_id_t 968d876124dSJohn Birrell ctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 969d876124dSJohn Birrell { 970d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE)); 971d876124dSJohn Birrell } 972d876124dSJohn Birrell 973d876124dSJohn Birrell ctf_id_t 974d876124dSJohn Birrell ctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 975d876124dSJohn Birrell { 976d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST)); 977d876124dSJohn Birrell } 978d876124dSJohn Birrell 979d876124dSJohn Birrell ctf_id_t 980d876124dSJohn Birrell ctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 981d876124dSJohn Birrell { 982d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT)); 983d876124dSJohn Birrell } 984d876124dSJohn Birrell 985d876124dSJohn Birrell int 986d876124dSJohn Birrell ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value) 987d876124dSJohn Birrell { 988d876124dSJohn Birrell ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid); 989d876124dSJohn Birrell ctf_dmdef_t *dmd; 990d876124dSJohn Birrell 991d876124dSJohn Birrell uint_t kind, vlen, root; 992d876124dSJohn Birrell char *s; 993d876124dSJohn Birrell 994d876124dSJohn Birrell if (name == NULL) 995d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 996d876124dSJohn Birrell 997d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 998d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 999d876124dSJohn Birrell 1000d876124dSJohn Birrell if (dtd == NULL) 1001d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_BADID)); 1002d876124dSJohn Birrell 1003d876124dSJohn Birrell kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 1004d876124dSJohn Birrell root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); 1005d876124dSJohn Birrell vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 1006d876124dSJohn Birrell 1007d876124dSJohn Birrell if (kind != CTF_K_ENUM) 1008d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_NOTENUM)); 1009d876124dSJohn Birrell 1010d876124dSJohn Birrell if (vlen == CTF_MAX_VLEN) 1011d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DTFULL)); 1012d876124dSJohn Birrell 1013d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1014d876124dSJohn Birrell dmd != NULL; dmd = ctf_list_next(dmd)) { 1015d876124dSJohn Birrell if (strcmp(dmd->dmd_name, name) == 0) 1016d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DUPMEMBER)); 1017d876124dSJohn Birrell } 1018d876124dSJohn Birrell 1019d876124dSJohn Birrell if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 1020d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 1021d876124dSJohn Birrell 1022d876124dSJohn Birrell if ((s = ctf_strdup(name)) == NULL) { 1023d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 1024d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 1025d876124dSJohn Birrell } 1026d876124dSJohn Birrell 1027d876124dSJohn Birrell dmd->dmd_name = s; 1028d876124dSJohn Birrell dmd->dmd_type = CTF_ERR; 1029d876124dSJohn Birrell dmd->dmd_offset = 0; 1030d876124dSJohn Birrell dmd->dmd_value = value; 1031d876124dSJohn Birrell 1032d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); 1033d876124dSJohn Birrell ctf_list_append(&dtd->dtd_u.dtu_members, dmd); 1034d876124dSJohn Birrell 1035d876124dSJohn Birrell fp->ctf_dtstrlen += strlen(s) + 1; 1036d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 1037d876124dSJohn Birrell 1038d876124dSJohn Birrell return (0); 1039d876124dSJohn Birrell } 1040d876124dSJohn Birrell 1041d876124dSJohn Birrell int 1042d876124dSJohn Birrell ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) 1043d876124dSJohn Birrell { 1044d876124dSJohn Birrell ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid); 1045d876124dSJohn Birrell ctf_dmdef_t *dmd; 1046d876124dSJohn Birrell 1047d876124dSJohn Birrell ssize_t msize, malign, ssize; 1048d876124dSJohn Birrell uint_t kind, vlen, root; 1049d876124dSJohn Birrell char *s = NULL; 1050d876124dSJohn Birrell 1051d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 1052d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 1053d876124dSJohn Birrell 1054d876124dSJohn Birrell if (dtd == NULL) 1055d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_BADID)); 1056d876124dSJohn Birrell 1057d876124dSJohn Birrell kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 1058d876124dSJohn Birrell root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); 1059d876124dSJohn Birrell vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 1060d876124dSJohn Birrell 1061d876124dSJohn Birrell if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 1062d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_NOTSOU)); 1063d876124dSJohn Birrell 1064d876124dSJohn Birrell if (vlen == CTF_MAX_VLEN) 1065d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DTFULL)); 1066d876124dSJohn Birrell 1067d876124dSJohn Birrell if (name != NULL) { 1068d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1069d876124dSJohn Birrell dmd != NULL; dmd = ctf_list_next(dmd)) { 1070d876124dSJohn Birrell if (dmd->dmd_name != NULL && 1071d876124dSJohn Birrell strcmp(dmd->dmd_name, name) == 0) 1072d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DUPMEMBER)); 1073d876124dSJohn Birrell } 1074d876124dSJohn Birrell } 1075d876124dSJohn Birrell 1076d876124dSJohn Birrell if ((msize = ctf_type_size(fp, type)) == CTF_ERR || 1077d876124dSJohn Birrell (malign = ctf_type_align(fp, type)) == CTF_ERR) 1078d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1079d876124dSJohn Birrell 1080d876124dSJohn Birrell if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 1081d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 1082d876124dSJohn Birrell 1083d876124dSJohn Birrell if (name != NULL && (s = ctf_strdup(name)) == NULL) { 1084d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 1085d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 1086d876124dSJohn Birrell } 1087d876124dSJohn Birrell 1088d876124dSJohn Birrell dmd->dmd_name = s; 1089d876124dSJohn Birrell dmd->dmd_type = type; 1090d876124dSJohn Birrell dmd->dmd_value = -1; 1091d876124dSJohn Birrell 1092d876124dSJohn Birrell if (kind == CTF_K_STRUCT && vlen != 0) { 1093d876124dSJohn Birrell ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members); 1094d876124dSJohn Birrell ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type); 1095d876124dSJohn Birrell size_t off = lmd->dmd_offset; 1096d876124dSJohn Birrell 1097d876124dSJohn Birrell ctf_encoding_t linfo; 1098d876124dSJohn Birrell ssize_t lsize; 1099d876124dSJohn Birrell 1100d876124dSJohn Birrell if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR) 1101d876124dSJohn Birrell off += linfo.cte_bits; 1102d876124dSJohn Birrell else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR) 1103d876124dSJohn Birrell off += lsize * NBBY; 1104d876124dSJohn Birrell 1105d876124dSJohn Birrell /* 1106d876124dSJohn Birrell * Round up the offset of the end of the last member to the 1107d876124dSJohn Birrell * next byte boundary, convert 'off' to bytes, and then round 1108d876124dSJohn Birrell * it up again to the next multiple of the alignment required 1109d876124dSJohn Birrell * by the new member. Finally, convert back to bits and store 1110d876124dSJohn Birrell * the result in dmd_offset. Technically we could do more 1111d876124dSJohn Birrell * efficient packing if the new member is a bit-field, but 1112d876124dSJohn Birrell * we're the "compiler" and ANSI says we can do as we choose. 1113d876124dSJohn Birrell */ 1114d876124dSJohn Birrell off = roundup(off, NBBY) / NBBY; 1115d876124dSJohn Birrell off = roundup(off, MAX(malign, 1)); 1116d876124dSJohn Birrell dmd->dmd_offset = off * NBBY; 1117d876124dSJohn Birrell ssize = off + msize; 1118d876124dSJohn Birrell } else { 1119d876124dSJohn Birrell dmd->dmd_offset = 0; 1120d876124dSJohn Birrell ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL); 1121d876124dSJohn Birrell ssize = MAX(ssize, msize); 1122d876124dSJohn Birrell } 1123d876124dSJohn Birrell 1124d876124dSJohn Birrell if (ssize > CTF_MAX_SIZE) { 1125d876124dSJohn Birrell dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; 1126d876124dSJohn Birrell dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize); 1127d876124dSJohn Birrell dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize); 1128d876124dSJohn Birrell } else 1129d876124dSJohn Birrell dtd->dtd_data.ctt_size = (ushort_t)ssize; 1130d876124dSJohn Birrell 1131d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); 1132d876124dSJohn Birrell ctf_list_append(&dtd->dtd_u.dtu_members, dmd); 1133d876124dSJohn Birrell 1134d876124dSJohn Birrell if (s != NULL) 1135d876124dSJohn Birrell fp->ctf_dtstrlen += strlen(s) + 1; 1136d876124dSJohn Birrell 11373f0164abSXin LI ctf_ref_inc(fp, type); 11383f0164abSXin LI fp->ctf_flags |= LCTF_DIRTY; 11393f0164abSXin LI return (0); 11403f0164abSXin LI } 11413f0164abSXin LI 11423f0164abSXin LI /* 11433f0164abSXin LI * This removes a type from the dynamic section. This will fail if the type is 11443f0164abSXin LI * referenced by another type. Note that the CTF ID is never reused currently by 11453f0164abSXin LI * CTF. Note that if this container is a parent container then we just outright 11463f0164abSXin LI * refuse to remove the type. There currently is no notion of searching for the 11473f0164abSXin LI * ctf_dtdef_t in parent containers. If there is, then this constraint could 11483f0164abSXin LI * become finer grained. 11493f0164abSXin LI */ 11503f0164abSXin LI int 11513f0164abSXin LI ctf_delete_type(ctf_file_t *fp, ctf_id_t type) 11523f0164abSXin LI { 11533f0164abSXin LI ctf_file_t *fpd; 11543f0164abSXin LI ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); 11553f0164abSXin LI 11563f0164abSXin LI if (!(fp->ctf_flags & LCTF_RDWR)) 11573f0164abSXin LI return (ctf_set_errno(fp, ECTF_RDONLY)); 11583f0164abSXin LI 11593f0164abSXin LI /* 11603f0164abSXin LI * We want to give as useful an errno as possible. That means that we 11613f0164abSXin LI * want to distinguish between a type which does not exist and one for 11623f0164abSXin LI * which the type is not dynamic. 11633f0164abSXin LI */ 11643f0164abSXin LI fpd = fp; 11653f0164abSXin LI if (ctf_lookup_by_id(&fpd, type) == NULL && 11663f0164abSXin LI ctf_dtd_lookup(fp, type) == NULL) 11673f0164abSXin LI return (CTF_ERR); /* errno is set for us */ 11683f0164abSXin LI 11693f0164abSXin LI if (dtd == NULL) 11703f0164abSXin LI return (ctf_set_errno(fp, ECTF_NOTDYN)); 11713f0164abSXin LI 11723f0164abSXin LI if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1) 11733f0164abSXin LI return (ctf_set_errno(fp, ECTF_REFERENCED)); 11743f0164abSXin LI 11753f0164abSXin LI ctf_dtd_delete(fp, dtd); 1176d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 1177d876124dSJohn Birrell return (0); 1178d876124dSJohn Birrell } 1179d876124dSJohn Birrell 1180d876124dSJohn Birrell static int 1181d876124dSJohn Birrell enumcmp(const char *name, int value, void *arg) 1182d876124dSJohn Birrell { 1183d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1184d876124dSJohn Birrell int bvalue; 1185d876124dSJohn Birrell 1186d876124dSJohn Birrell return (ctf_enum_value(ctb->ctb_file, ctb->ctb_type, 1187d876124dSJohn Birrell name, &bvalue) == CTF_ERR || value != bvalue); 1188d876124dSJohn Birrell } 1189d876124dSJohn Birrell 1190d876124dSJohn Birrell static int 1191d876124dSJohn Birrell enumadd(const char *name, int value, void *arg) 1192d876124dSJohn Birrell { 1193d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1194d876124dSJohn Birrell 1195d876124dSJohn Birrell return (ctf_add_enumerator(ctb->ctb_file, ctb->ctb_type, 1196d876124dSJohn Birrell name, value) == CTF_ERR); 1197d876124dSJohn Birrell } 1198d876124dSJohn Birrell 1199d876124dSJohn Birrell /*ARGSUSED*/ 1200d876124dSJohn Birrell static int 1201d876124dSJohn Birrell membcmp(const char *name, ctf_id_t type, ulong_t offset, void *arg) 1202d876124dSJohn Birrell { 1203d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1204d876124dSJohn Birrell ctf_membinfo_t ctm; 1205d876124dSJohn Birrell 1206d876124dSJohn Birrell return (ctf_member_info(ctb->ctb_file, ctb->ctb_type, 1207d876124dSJohn Birrell name, &ctm) == CTF_ERR || ctm.ctm_offset != offset); 1208d876124dSJohn Birrell } 1209d876124dSJohn Birrell 1210d876124dSJohn Birrell static int 1211d876124dSJohn Birrell membadd(const char *name, ctf_id_t type, ulong_t offset, void *arg) 1212d876124dSJohn Birrell { 1213d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1214d876124dSJohn Birrell ctf_dmdef_t *dmd; 1215d876124dSJohn Birrell char *s = NULL; 1216d876124dSJohn Birrell 1217d876124dSJohn Birrell if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 1218d876124dSJohn Birrell return (ctf_set_errno(ctb->ctb_file, EAGAIN)); 1219d876124dSJohn Birrell 1220d876124dSJohn Birrell if (name != NULL && (s = ctf_strdup(name)) == NULL) { 1221d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 1222d876124dSJohn Birrell return (ctf_set_errno(ctb->ctb_file, EAGAIN)); 1223d876124dSJohn Birrell } 1224d876124dSJohn Birrell 1225d876124dSJohn Birrell /* 1226d876124dSJohn Birrell * For now, dmd_type is copied as the src_fp's type; it is reset to an 1227d876124dSJohn Birrell * equivalent dst_fp type by a final loop in ctf_add_type(), below. 1228d876124dSJohn Birrell */ 1229d876124dSJohn Birrell dmd->dmd_name = s; 1230d876124dSJohn Birrell dmd->dmd_type = type; 1231d876124dSJohn Birrell dmd->dmd_offset = offset; 1232d876124dSJohn Birrell dmd->dmd_value = -1; 1233d876124dSJohn Birrell 1234d876124dSJohn Birrell ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd); 1235d876124dSJohn Birrell 1236d876124dSJohn Birrell if (s != NULL) 1237d876124dSJohn Birrell ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1; 1238d876124dSJohn Birrell 1239d876124dSJohn Birrell ctb->ctb_file->ctf_flags |= LCTF_DIRTY; 1240d876124dSJohn Birrell return (0); 1241d876124dSJohn Birrell } 1242d876124dSJohn Birrell 1243d876124dSJohn Birrell /* 1244d876124dSJohn Birrell * The ctf_add_type routine is used to copy a type from a source CTF container 1245d876124dSJohn Birrell * to a dynamic destination container. This routine operates recursively by 1246d876124dSJohn Birrell * following the source type's links and embedded member types. If the 1247d876124dSJohn Birrell * destination container already contains a named type which has the same 1248d876124dSJohn Birrell * attributes, then we succeed and return this type but no changes occur. 1249d876124dSJohn Birrell */ 1250d876124dSJohn Birrell ctf_id_t 1251d876124dSJohn Birrell ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) 1252d876124dSJohn Birrell { 1253d876124dSJohn Birrell ctf_id_t dst_type = CTF_ERR; 1254d876124dSJohn Birrell uint_t dst_kind = CTF_K_UNKNOWN; 1255d876124dSJohn Birrell 1256d876124dSJohn Birrell const ctf_type_t *tp; 1257d876124dSJohn Birrell const char *name; 1258d876124dSJohn Birrell uint_t kind, flag, vlen; 1259d876124dSJohn Birrell 1260d876124dSJohn Birrell ctf_bundle_t src, dst; 1261d876124dSJohn Birrell ctf_encoding_t src_en, dst_en; 1262d876124dSJohn Birrell ctf_arinfo_t src_ar, dst_ar; 1263d876124dSJohn Birrell 1264d876124dSJohn Birrell ctf_dtdef_t *dtd; 1265d876124dSJohn Birrell ctf_funcinfo_t ctc; 1266d876124dSJohn Birrell ssize_t size; 1267d876124dSJohn Birrell 1268d876124dSJohn Birrell ctf_hash_t *hp; 1269d876124dSJohn Birrell ctf_helem_t *hep; 1270d876124dSJohn Birrell 12713f0164abSXin LI if (dst_fp == src_fp) 12723f0164abSXin LI return (src_type); 12733f0164abSXin LI 1274d876124dSJohn Birrell if (!(dst_fp->ctf_flags & LCTF_RDWR)) 1275d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_RDONLY)); 1276d876124dSJohn Birrell 1277d876124dSJohn Birrell if ((tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL) 1278d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 1279d876124dSJohn Birrell 1280d876124dSJohn Birrell name = ctf_strptr(src_fp, tp->ctt_name); 1281d876124dSJohn Birrell kind = LCTF_INFO_KIND(src_fp, tp->ctt_info); 1282d876124dSJohn Birrell flag = LCTF_INFO_ROOT(src_fp, tp->ctt_info); 1283d876124dSJohn Birrell vlen = LCTF_INFO_VLEN(src_fp, tp->ctt_info); 1284d876124dSJohn Birrell 1285d876124dSJohn Birrell switch (kind) { 1286d876124dSJohn Birrell case CTF_K_STRUCT: 1287d876124dSJohn Birrell hp = &dst_fp->ctf_structs; 1288d876124dSJohn Birrell break; 1289d876124dSJohn Birrell case CTF_K_UNION: 1290d876124dSJohn Birrell hp = &dst_fp->ctf_unions; 1291d876124dSJohn Birrell break; 1292d876124dSJohn Birrell case CTF_K_ENUM: 1293d876124dSJohn Birrell hp = &dst_fp->ctf_enums; 1294d876124dSJohn Birrell break; 1295d876124dSJohn Birrell default: 1296d876124dSJohn Birrell hp = &dst_fp->ctf_names; 1297d876124dSJohn Birrell break; 1298d876124dSJohn Birrell } 1299d876124dSJohn Birrell 1300d876124dSJohn Birrell /* 1301d876124dSJohn Birrell * If the source type has a name and is a root type (visible at the 1302d876124dSJohn Birrell * top-level scope), lookup the name in the destination container and 1303d876124dSJohn Birrell * verify that it is of the same kind before we do anything else. 1304d876124dSJohn Birrell */ 1305d876124dSJohn Birrell if ((flag & CTF_ADD_ROOT) && name[0] != '\0' && 1306d876124dSJohn Birrell (hep = ctf_hash_lookup(hp, dst_fp, name, strlen(name))) != NULL) { 1307d876124dSJohn Birrell dst_type = (ctf_id_t)hep->h_type; 1308d876124dSJohn Birrell dst_kind = ctf_type_kind(dst_fp, dst_type); 1309d876124dSJohn Birrell } 1310d876124dSJohn Birrell 1311d876124dSJohn Birrell /* 1312d876124dSJohn Birrell * If an identically named dst_type exists, fail with ECTF_CONFLICT 1313d876124dSJohn Birrell * unless dst_type is a forward declaration and src_type is a struct, 1314d876124dSJohn Birrell * union, or enum (i.e. the definition of the previous forward decl). 1315d876124dSJohn Birrell */ 1316f810bf0eSMark Johnston if (dst_type != CTF_ERR && dst_kind != kind) { 1317f810bf0eSMark Johnston if (dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM && 1318f810bf0eSMark Johnston kind != CTF_K_STRUCT && kind != CTF_K_UNION)) 1319d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1320f810bf0eSMark Johnston else 1321f810bf0eSMark Johnston dst_type = CTF_ERR; 1322f810bf0eSMark Johnston } 1323d876124dSJohn Birrell 1324d876124dSJohn Birrell /* 1325d876124dSJohn Birrell * If the non-empty name was not found in the appropriate hash, search 1326d876124dSJohn Birrell * the list of pending dynamic definitions that are not yet committed. 1327d876124dSJohn Birrell * If a matching name and kind are found, assume this is the type that 1328d876124dSJohn Birrell * we are looking for. This is necessary to permit ctf_add_type() to 1329d876124dSJohn Birrell * operate recursively on entities such as a struct that contains a 1330d876124dSJohn Birrell * pointer member that refers to the same struct type. 1331*3e5645b7SMark Johnston * 1332*3e5645b7SMark Johnston * In the case of integer and floating point types, we match using the 1333*3e5645b7SMark Johnston * type encoding as well - else we may incorrectly return a bitfield 1334*3e5645b7SMark Johnston * type, for instance. 1335d876124dSJohn Birrell */ 1336d876124dSJohn Birrell if (dst_type == CTF_ERR && name[0] != '\0') { 1337d876124dSJohn Birrell for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL && 1338b0ee9129SMark Johnston CTF_TYPE_TO_INDEX(dtd->dtd_type) > dst_fp->ctf_dtoldid; 1339d876124dSJohn Birrell dtd = ctf_list_prev(dtd)) { 1340*3e5645b7SMark Johnston if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != kind || 1341*3e5645b7SMark Johnston dtd->dtd_name == NULL || 1342*3e5645b7SMark Johnston strcmp(dtd->dtd_name, name) != 0) 1343*3e5645b7SMark Johnston continue; 1344*3e5645b7SMark Johnston if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) { 1345*3e5645b7SMark Johnston if (ctf_type_encoding(src_fp, src_type, 1346*3e5645b7SMark Johnston &src_en) != 0) 1347*3e5645b7SMark Johnston continue; 1348*3e5645b7SMark Johnston if (bcmp(&src_en, &dtd->dtd_u.dtu_enc, 1349*3e5645b7SMark Johnston sizeof (ctf_encoding_t)) != 0) 1350*3e5645b7SMark Johnston continue; 1351*3e5645b7SMark Johnston } 1352d876124dSJohn Birrell return (dtd->dtd_type); 1353d876124dSJohn Birrell } 1354d876124dSJohn Birrell } 1355d876124dSJohn Birrell 1356d876124dSJohn Birrell src.ctb_file = src_fp; 1357d876124dSJohn Birrell src.ctb_type = src_type; 1358d876124dSJohn Birrell src.ctb_dtd = NULL; 1359d876124dSJohn Birrell 1360d876124dSJohn Birrell dst.ctb_file = dst_fp; 1361d876124dSJohn Birrell dst.ctb_type = dst_type; 1362d876124dSJohn Birrell dst.ctb_dtd = NULL; 1363d876124dSJohn Birrell 1364d876124dSJohn Birrell /* 1365d876124dSJohn Birrell * Now perform kind-specific processing. If dst_type is CTF_ERR, then 1366d876124dSJohn Birrell * we add a new type with the same properties as src_type to dst_fp. 1367d876124dSJohn Birrell * If dst_type is not CTF_ERR, then we verify that dst_type has the 1368d876124dSJohn Birrell * same attributes as src_type. We recurse for embedded references. 1369d876124dSJohn Birrell */ 1370d876124dSJohn Birrell switch (kind) { 1371d876124dSJohn Birrell case CTF_K_INTEGER: 1372d876124dSJohn Birrell case CTF_K_FLOAT: 1373d876124dSJohn Birrell if (ctf_type_encoding(src_fp, src_type, &src_en) != 0) 1374d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 1375d876124dSJohn Birrell 1376d876124dSJohn Birrell if (dst_type != CTF_ERR) { 1377d876124dSJohn Birrell if (ctf_type_encoding(dst_fp, dst_type, &dst_en) != 0) 1378d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1379d876124dSJohn Birrell 1380d876124dSJohn Birrell if (bcmp(&src_en, &dst_en, sizeof (ctf_encoding_t))) 1381d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1382d876124dSJohn Birrell 1383d876124dSJohn Birrell } else if (kind == CTF_K_INTEGER) { 1384d876124dSJohn Birrell dst_type = ctf_add_integer(dst_fp, flag, name, &src_en); 1385d876124dSJohn Birrell } else 1386d876124dSJohn Birrell dst_type = ctf_add_float(dst_fp, flag, name, &src_en); 1387d876124dSJohn Birrell break; 1388d876124dSJohn Birrell 1389d876124dSJohn Birrell case CTF_K_POINTER: 1390d876124dSJohn Birrell case CTF_K_VOLATILE: 1391d876124dSJohn Birrell case CTF_K_CONST: 1392d876124dSJohn Birrell case CTF_K_RESTRICT: 1393d876124dSJohn Birrell src_type = ctf_type_reference(src_fp, src_type); 1394d876124dSJohn Birrell src_type = ctf_add_type(dst_fp, src_fp, src_type); 1395d876124dSJohn Birrell 1396d876124dSJohn Birrell if (src_type == CTF_ERR) 1397d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1398d876124dSJohn Birrell 1399d876124dSJohn Birrell dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind); 1400d876124dSJohn Birrell break; 1401d876124dSJohn Birrell 1402d876124dSJohn Birrell case CTF_K_ARRAY: 1403d876124dSJohn Birrell if (ctf_array_info(src_fp, src_type, &src_ar) == CTF_ERR) 1404d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 1405d876124dSJohn Birrell 1406d876124dSJohn Birrell src_ar.ctr_contents = 1407d876124dSJohn Birrell ctf_add_type(dst_fp, src_fp, src_ar.ctr_contents); 1408d876124dSJohn Birrell src_ar.ctr_index = 1409d876124dSJohn Birrell ctf_add_type(dst_fp, src_fp, src_ar.ctr_index); 1410d876124dSJohn Birrell src_ar.ctr_nelems = src_ar.ctr_nelems; 1411d876124dSJohn Birrell 1412d876124dSJohn Birrell if (src_ar.ctr_contents == CTF_ERR || 1413d876124dSJohn Birrell src_ar.ctr_index == CTF_ERR) 1414d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1415d876124dSJohn Birrell 1416d876124dSJohn Birrell if (dst_type != CTF_ERR) { 1417d876124dSJohn Birrell if (ctf_array_info(dst_fp, dst_type, &dst_ar) != 0) 1418d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1419d876124dSJohn Birrell 1420d876124dSJohn Birrell if (bcmp(&src_ar, &dst_ar, sizeof (ctf_arinfo_t))) 1421d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1422d876124dSJohn Birrell } else 1423d876124dSJohn Birrell dst_type = ctf_add_array(dst_fp, flag, &src_ar); 1424d876124dSJohn Birrell break; 1425d876124dSJohn Birrell 1426d876124dSJohn Birrell case CTF_K_FUNCTION: 1427d876124dSJohn Birrell ctc.ctc_return = ctf_add_type(dst_fp, src_fp, tp->ctt_type); 1428d876124dSJohn Birrell ctc.ctc_argc = 0; 1429d876124dSJohn Birrell ctc.ctc_flags = 0; 1430d876124dSJohn Birrell 1431d876124dSJohn Birrell if (ctc.ctc_return == CTF_ERR) 1432d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1433d876124dSJohn Birrell 1434d876124dSJohn Birrell dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL); 1435d876124dSJohn Birrell break; 1436d876124dSJohn Birrell 1437d876124dSJohn Birrell case CTF_K_STRUCT: 1438d876124dSJohn Birrell case CTF_K_UNION: { 1439d876124dSJohn Birrell ctf_dmdef_t *dmd; 1440d876124dSJohn Birrell int errs = 0; 1441d876124dSJohn Birrell 1442d876124dSJohn Birrell /* 1443d876124dSJohn Birrell * Technically to match a struct or union we need to check both 1444d876124dSJohn Birrell * ways (src members vs. dst, dst members vs. src) but we make 1445d876124dSJohn Birrell * this more optimal by only checking src vs. dst and comparing 1446d876124dSJohn Birrell * the total size of the structure (which we must do anyway) 1447d876124dSJohn Birrell * which covers the possibility of dst members not in src. 1448d876124dSJohn Birrell * This optimization can be defeated for unions, but is so 1449d876124dSJohn Birrell * pathological as to render it irrelevant for our purposes. 1450d876124dSJohn Birrell */ 1451d876124dSJohn Birrell if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { 1452d876124dSJohn Birrell if (ctf_type_size(src_fp, src_type) != 1453d876124dSJohn Birrell ctf_type_size(dst_fp, dst_type)) 1454d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1455d876124dSJohn Birrell 1456d876124dSJohn Birrell if (ctf_member_iter(src_fp, src_type, membcmp, &dst)) 1457d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1458d876124dSJohn Birrell 1459d876124dSJohn Birrell break; 1460d876124dSJohn Birrell } 1461d876124dSJohn Birrell 1462d876124dSJohn Birrell /* 1463d876124dSJohn Birrell * Unlike the other cases, copying structs and unions is done 1464d876124dSJohn Birrell * manually so as to avoid repeated lookups in ctf_add_member 1465d876124dSJohn Birrell * and to ensure the exact same member offsets as in src_type. 1466d876124dSJohn Birrell */ 1467d876124dSJohn Birrell dst_type = ctf_add_generic(dst_fp, flag, name, &dtd); 1468d876124dSJohn Birrell if (dst_type == CTF_ERR) 1469d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1470d876124dSJohn Birrell 1471d876124dSJohn Birrell dst.ctb_type = dst_type; 1472d876124dSJohn Birrell dst.ctb_dtd = dtd; 1473d876124dSJohn Birrell 1474d876124dSJohn Birrell if (ctf_member_iter(src_fp, src_type, membadd, &dst) != 0) 1475d876124dSJohn Birrell errs++; /* increment errs and fail at bottom of case */ 1476d876124dSJohn Birrell 1477d876124dSJohn Birrell if ((size = ctf_type_size(src_fp, src_type)) > CTF_MAX_SIZE) { 1478d876124dSJohn Birrell dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; 1479d876124dSJohn Birrell dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size); 1480d876124dSJohn Birrell dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size); 1481d876124dSJohn Birrell } else 1482d876124dSJohn Birrell dtd->dtd_data.ctt_size = (ushort_t)size; 1483d876124dSJohn Birrell 1484d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, vlen); 1485d876124dSJohn Birrell 1486d876124dSJohn Birrell /* 1487d876124dSJohn Birrell * Make a final pass through the members changing each dmd_type 1488d876124dSJohn Birrell * (a src_fp type) to an equivalent type in dst_fp. We pass 1489d876124dSJohn Birrell * through all members, leaving any that fail set to CTF_ERR. 1490d876124dSJohn Birrell */ 1491d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1492d876124dSJohn Birrell dmd != NULL; dmd = ctf_list_next(dmd)) { 1493d876124dSJohn Birrell if ((dmd->dmd_type = ctf_add_type(dst_fp, src_fp, 1494d876124dSJohn Birrell dmd->dmd_type)) == CTF_ERR) 1495d876124dSJohn Birrell errs++; 1496d876124dSJohn Birrell } 1497d876124dSJohn Birrell 1498d876124dSJohn Birrell if (errs) 1499d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 15003f0164abSXin LI 15013f0164abSXin LI /* 15023f0164abSXin LI * Now that we know that we can't fail, we go through and bump 15033f0164abSXin LI * all the reference counts on the member types. 15043f0164abSXin LI */ 15053f0164abSXin LI for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 15063f0164abSXin LI dmd != NULL; dmd = ctf_list_next(dmd)) 15073f0164abSXin LI ctf_ref_inc(dst_fp, dmd->dmd_type); 1508d876124dSJohn Birrell break; 1509d876124dSJohn Birrell } 1510d876124dSJohn Birrell 1511d876124dSJohn Birrell case CTF_K_ENUM: 1512d876124dSJohn Birrell if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { 1513d876124dSJohn Birrell if (ctf_enum_iter(src_fp, src_type, enumcmp, &dst) || 1514d876124dSJohn Birrell ctf_enum_iter(dst_fp, dst_type, enumcmp, &src)) 1515d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1516d876124dSJohn Birrell } else { 1517d876124dSJohn Birrell dst_type = ctf_add_enum(dst_fp, flag, name); 1518d876124dSJohn Birrell if ((dst.ctb_type = dst_type) == CTF_ERR || 1519d876124dSJohn Birrell ctf_enum_iter(src_fp, src_type, enumadd, &dst)) 1520d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1521d876124dSJohn Birrell } 1522d876124dSJohn Birrell break; 1523d876124dSJohn Birrell 1524d876124dSJohn Birrell case CTF_K_FORWARD: 1525d876124dSJohn Birrell if (dst_type == CTF_ERR) { 1526d876124dSJohn Birrell dst_type = ctf_add_forward(dst_fp, 1527d876124dSJohn Birrell flag, name, CTF_K_STRUCT); /* assume STRUCT */ 1528d876124dSJohn Birrell } 1529d876124dSJohn Birrell break; 1530d876124dSJohn Birrell 1531d876124dSJohn Birrell case CTF_K_TYPEDEF: 1532d876124dSJohn Birrell src_type = ctf_type_reference(src_fp, src_type); 1533d876124dSJohn Birrell src_type = ctf_add_type(dst_fp, src_fp, src_type); 1534d876124dSJohn Birrell 1535d876124dSJohn Birrell if (src_type == CTF_ERR) 1536d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1537d876124dSJohn Birrell 1538d876124dSJohn Birrell /* 1539d876124dSJohn Birrell * If dst_type is not CTF_ERR at this point, we should check if 1540d876124dSJohn Birrell * ctf_type_reference(dst_fp, dst_type) != src_type and if so 1541d876124dSJohn Birrell * fail with ECTF_CONFLICT. However, this causes problems with 1542d876124dSJohn Birrell * <sys/types.h> typedefs that vary based on things like if 1543d876124dSJohn Birrell * _ILP32x then pid_t is int otherwise long. We therefore omit 1544d876124dSJohn Birrell * this check and assume that if the identically named typedef 1545d876124dSJohn Birrell * already exists in dst_fp, it is correct or equivalent. 1546d876124dSJohn Birrell */ 1547d876124dSJohn Birrell if (dst_type == CTF_ERR) { 1548d876124dSJohn Birrell dst_type = ctf_add_typedef(dst_fp, flag, 1549d876124dSJohn Birrell name, src_type); 1550d876124dSJohn Birrell } 1551d876124dSJohn Birrell break; 1552d876124dSJohn Birrell 1553d876124dSJohn Birrell default: 1554d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CORRUPT)); 1555d876124dSJohn Birrell } 1556d876124dSJohn Birrell 1557d876124dSJohn Birrell return (dst_type); 1558d876124dSJohn Birrell } 1559