1*d876124dSJohn Birrell /* 2*d876124dSJohn Birrell * CDDL HEADER START 3*d876124dSJohn Birrell * 4*d876124dSJohn Birrell * The contents of this file are subject to the terms of the 5*d876124dSJohn Birrell * Common Development and Distribution License, Version 1.0 only 6*d876124dSJohn Birrell * (the "License"). You may not use this file except in compliance 7*d876124dSJohn Birrell * with the License. 8*d876124dSJohn Birrell * 9*d876124dSJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*d876124dSJohn Birrell * or http://www.opensolaris.org/os/licensing. 11*d876124dSJohn Birrell * See the License for the specific language governing permissions 12*d876124dSJohn Birrell * and limitations under the License. 13*d876124dSJohn Birrell * 14*d876124dSJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 15*d876124dSJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*d876124dSJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 17*d876124dSJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 18*d876124dSJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 19*d876124dSJohn Birrell * 20*d876124dSJohn Birrell * CDDL HEADER END 21*d876124dSJohn Birrell */ 22*d876124dSJohn Birrell 23*d876124dSJohn Birrell /* 24*d876124dSJohn Birrell * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25*d876124dSJohn Birrell * Use is subject to license terms. 26*d876124dSJohn Birrell */ 27*d876124dSJohn Birrell 28*d876124dSJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 29*d876124dSJohn Birrell 30*d876124dSJohn Birrell #include <sys/sysmacros.h> 31*d876124dSJohn Birrell #include <sys/param.h> 32*d876124dSJohn Birrell #include <sys/mman.h> 33*d876124dSJohn Birrell #include <ctf_impl.h> 34*d876124dSJohn Birrell 35*d876124dSJohn Birrell /* 36*d876124dSJohn Birrell * This static string is used as the template for initially populating a 37*d876124dSJohn Birrell * dynamic container's string table. We always store \0 in the first byte, 38*d876124dSJohn Birrell * and we use the generic string "PARENT" to mark this container's parent 39*d876124dSJohn Birrell * if one is associated with the container using ctf_import(). 40*d876124dSJohn Birrell */ 41*d876124dSJohn Birrell static const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT"; 42*d876124dSJohn Birrell 43*d876124dSJohn Birrell /* 44*d876124dSJohn Birrell * To create an empty CTF container, we just declare a zeroed header and call 45*d876124dSJohn Birrell * ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w 46*d876124dSJohn Birrell * and initialize the dynamic members. We set dtstrlen to 1 to reserve the 47*d876124dSJohn Birrell * first byte of the string table for a \0 byte, and we start assigning type 48*d876124dSJohn Birrell * IDs at 1 because type ID 0 is used as a sentinel. 49*d876124dSJohn Birrell */ 50*d876124dSJohn Birrell ctf_file_t * 51*d876124dSJohn Birrell ctf_create(int *errp) 52*d876124dSJohn Birrell { 53*d876124dSJohn Birrell static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } }; 54*d876124dSJohn Birrell 55*d876124dSJohn Birrell const ulong_t hashlen = 128; 56*d876124dSJohn Birrell ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *)); 57*d876124dSJohn Birrell ctf_sect_t cts; 58*d876124dSJohn Birrell ctf_file_t *fp; 59*d876124dSJohn Birrell 60*d876124dSJohn Birrell if (hash == NULL) 61*d876124dSJohn Birrell return (ctf_set_open_errno(errp, EAGAIN)); 62*d876124dSJohn Birrell 63*d876124dSJohn Birrell cts.cts_name = _CTF_SECTION; 64*d876124dSJohn Birrell cts.cts_type = SHT_PROGBITS; 65*d876124dSJohn Birrell cts.cts_flags = 0; 66*d876124dSJohn Birrell cts.cts_data = &hdr; 67*d876124dSJohn Birrell cts.cts_size = sizeof (hdr); 68*d876124dSJohn Birrell cts.cts_entsize = 1; 69*d876124dSJohn Birrell cts.cts_offset = 0; 70*d876124dSJohn Birrell 71*d876124dSJohn Birrell if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) { 72*d876124dSJohn Birrell ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *)); 73*d876124dSJohn Birrell return (NULL); 74*d876124dSJohn Birrell } 75*d876124dSJohn Birrell 76*d876124dSJohn Birrell fp->ctf_flags |= LCTF_RDWR; 77*d876124dSJohn Birrell fp->ctf_dthashlen = hashlen; 78*d876124dSJohn Birrell bzero(hash, hashlen * sizeof (ctf_dtdef_t *)); 79*d876124dSJohn Birrell fp->ctf_dthash = hash; 80*d876124dSJohn Birrell fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE); 81*d876124dSJohn Birrell fp->ctf_dtnextid = 1; 82*d876124dSJohn Birrell fp->ctf_dtoldid = 0; 83*d876124dSJohn Birrell 84*d876124dSJohn Birrell return (fp); 85*d876124dSJohn Birrell } 86*d876124dSJohn Birrell 87*d876124dSJohn Birrell static uchar_t * 88*d876124dSJohn Birrell ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 89*d876124dSJohn Birrell { 90*d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 91*d876124dSJohn Birrell ctf_member_t ctm; 92*d876124dSJohn Birrell 93*d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 94*d876124dSJohn Birrell if (dmd->dmd_name) { 95*d876124dSJohn Birrell ctm.ctm_name = soff; 96*d876124dSJohn Birrell soff += strlen(dmd->dmd_name) + 1; 97*d876124dSJohn Birrell } else 98*d876124dSJohn Birrell ctm.ctm_name = 0; 99*d876124dSJohn Birrell 100*d876124dSJohn Birrell ctm.ctm_type = (ushort_t)dmd->dmd_type; 101*d876124dSJohn Birrell ctm.ctm_offset = (ushort_t)dmd->dmd_offset; 102*d876124dSJohn Birrell 103*d876124dSJohn Birrell bcopy(&ctm, t, sizeof (ctm)); 104*d876124dSJohn Birrell t += sizeof (ctm); 105*d876124dSJohn Birrell } 106*d876124dSJohn Birrell 107*d876124dSJohn Birrell return (t); 108*d876124dSJohn Birrell } 109*d876124dSJohn Birrell 110*d876124dSJohn Birrell static uchar_t * 111*d876124dSJohn Birrell ctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 112*d876124dSJohn Birrell { 113*d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 114*d876124dSJohn Birrell ctf_lmember_t ctlm; 115*d876124dSJohn Birrell 116*d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 117*d876124dSJohn Birrell if (dmd->dmd_name) { 118*d876124dSJohn Birrell ctlm.ctlm_name = soff; 119*d876124dSJohn Birrell soff += strlen(dmd->dmd_name) + 1; 120*d876124dSJohn Birrell } else 121*d876124dSJohn Birrell ctlm.ctlm_name = 0; 122*d876124dSJohn Birrell 123*d876124dSJohn Birrell ctlm.ctlm_type = (ushort_t)dmd->dmd_type; 124*d876124dSJohn Birrell ctlm.ctlm_pad = 0; 125*d876124dSJohn Birrell ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); 126*d876124dSJohn Birrell ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); 127*d876124dSJohn Birrell 128*d876124dSJohn Birrell bcopy(&ctlm, t, sizeof (ctlm)); 129*d876124dSJohn Birrell t += sizeof (ctlm); 130*d876124dSJohn Birrell } 131*d876124dSJohn Birrell 132*d876124dSJohn Birrell return (t); 133*d876124dSJohn Birrell } 134*d876124dSJohn Birrell 135*d876124dSJohn Birrell static uchar_t * 136*d876124dSJohn Birrell ctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) 137*d876124dSJohn Birrell { 138*d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 139*d876124dSJohn Birrell ctf_enum_t cte; 140*d876124dSJohn Birrell 141*d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 142*d876124dSJohn Birrell cte.cte_name = soff; 143*d876124dSJohn Birrell cte.cte_value = dmd->dmd_value; 144*d876124dSJohn Birrell soff += strlen(dmd->dmd_name) + 1; 145*d876124dSJohn Birrell bcopy(&cte, t, sizeof (cte)); 146*d876124dSJohn Birrell t += sizeof (cte); 147*d876124dSJohn Birrell } 148*d876124dSJohn Birrell 149*d876124dSJohn Birrell return (t); 150*d876124dSJohn Birrell } 151*d876124dSJohn Birrell 152*d876124dSJohn Birrell static uchar_t * 153*d876124dSJohn Birrell ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) 154*d876124dSJohn Birrell { 155*d876124dSJohn Birrell ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 156*d876124dSJohn Birrell size_t len; 157*d876124dSJohn Birrell 158*d876124dSJohn Birrell for (; dmd != NULL; dmd = ctf_list_next(dmd)) { 159*d876124dSJohn Birrell if (dmd->dmd_name == NULL) 160*d876124dSJohn Birrell continue; /* skip anonymous members */ 161*d876124dSJohn Birrell len = strlen(dmd->dmd_name) + 1; 162*d876124dSJohn Birrell bcopy(dmd->dmd_name, s, len); 163*d876124dSJohn Birrell s += len; 164*d876124dSJohn Birrell } 165*d876124dSJohn Birrell 166*d876124dSJohn Birrell return (s); 167*d876124dSJohn Birrell } 168*d876124dSJohn Birrell 169*d876124dSJohn Birrell /* 170*d876124dSJohn Birrell * If the specified CTF container is writable and has been modified, reload 171*d876124dSJohn Birrell * this container with the updated type definitions. In order to make this 172*d876124dSJohn Birrell * code and the rest of libctf as simple as possible, we perform updates by 173*d876124dSJohn Birrell * taking the dynamic type definitions and creating an in-memory CTF file 174*d876124dSJohn Birrell * containing the definitions, and then call ctf_bufopen() on it. This not 175*d876124dSJohn Birrell * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest 176*d876124dSJohn Birrell * of the library code with different lookup paths for static and dynamic 177*d876124dSJohn Birrell * type definitions. We are therefore optimizing greatly for lookup over 178*d876124dSJohn Birrell * update, which we assume will be an uncommon operation. We perform one 179*d876124dSJohn Birrell * extra trick here for the benefit of callers and to keep our code simple: 180*d876124dSJohn Birrell * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp 181*d876124dSJohn Birrell * constant for the caller, so after ctf_bufopen() returns, we use bcopy to 182*d876124dSJohn Birrell * swap the interior of the old and new ctf_file_t's, and then free the old. 183*d876124dSJohn Birrell */ 184*d876124dSJohn Birrell int 185*d876124dSJohn Birrell ctf_update(ctf_file_t *fp) 186*d876124dSJohn Birrell { 187*d876124dSJohn Birrell ctf_file_t ofp, *nfp; 188*d876124dSJohn Birrell ctf_header_t hdr; 189*d876124dSJohn Birrell ctf_dtdef_t *dtd; 190*d876124dSJohn Birrell ctf_sect_t cts; 191*d876124dSJohn Birrell 192*d876124dSJohn Birrell uchar_t *s, *s0, *t; 193*d876124dSJohn Birrell size_t size; 194*d876124dSJohn Birrell void *buf; 195*d876124dSJohn Birrell int err; 196*d876124dSJohn Birrell 197*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 198*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 199*d876124dSJohn Birrell 200*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_DIRTY)) 201*d876124dSJohn Birrell return (0); /* no update required */ 202*d876124dSJohn Birrell 203*d876124dSJohn Birrell /* 204*d876124dSJohn Birrell * Fill in an initial CTF header. We will leave the label, object, 205*d876124dSJohn Birrell * and function sections empty and only output a header, type section, 206*d876124dSJohn Birrell * and string table. The type section begins at a 4-byte aligned 207*d876124dSJohn Birrell * boundary past the CTF header itself (at relative offset zero). 208*d876124dSJohn Birrell */ 209*d876124dSJohn Birrell bzero(&hdr, sizeof (hdr)); 210*d876124dSJohn Birrell hdr.cth_magic = CTF_MAGIC; 211*d876124dSJohn Birrell hdr.cth_version = CTF_VERSION; 212*d876124dSJohn Birrell 213*d876124dSJohn Birrell if (fp->ctf_flags & LCTF_CHILD) 214*d876124dSJohn Birrell hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */ 215*d876124dSJohn Birrell 216*d876124dSJohn Birrell /* 217*d876124dSJohn Birrell * Iterate through the dynamic type definition list and compute the 218*d876124dSJohn Birrell * size of the CTF type section we will need to generate. 219*d876124dSJohn Birrell */ 220*d876124dSJohn Birrell for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs); 221*d876124dSJohn Birrell dtd != NULL; dtd = ctf_list_next(dtd)) { 222*d876124dSJohn Birrell 223*d876124dSJohn Birrell uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 224*d876124dSJohn Birrell uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 225*d876124dSJohn Birrell 226*d876124dSJohn Birrell if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) 227*d876124dSJohn Birrell size += sizeof (ctf_stype_t); 228*d876124dSJohn Birrell else 229*d876124dSJohn Birrell size += sizeof (ctf_type_t); 230*d876124dSJohn Birrell 231*d876124dSJohn Birrell switch (kind) { 232*d876124dSJohn Birrell case CTF_K_INTEGER: 233*d876124dSJohn Birrell case CTF_K_FLOAT: 234*d876124dSJohn Birrell size += sizeof (uint_t); 235*d876124dSJohn Birrell break; 236*d876124dSJohn Birrell case CTF_K_ARRAY: 237*d876124dSJohn Birrell size += sizeof (ctf_array_t); 238*d876124dSJohn Birrell break; 239*d876124dSJohn Birrell case CTF_K_FUNCTION: 240*d876124dSJohn Birrell size += sizeof (ushort_t) * (vlen + (vlen & 1)); 241*d876124dSJohn Birrell break; 242*d876124dSJohn Birrell case CTF_K_STRUCT: 243*d876124dSJohn Birrell case CTF_K_UNION: 244*d876124dSJohn Birrell if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) 245*d876124dSJohn Birrell size += sizeof (ctf_member_t) * vlen; 246*d876124dSJohn Birrell else 247*d876124dSJohn Birrell size += sizeof (ctf_lmember_t) * vlen; 248*d876124dSJohn Birrell break; 249*d876124dSJohn Birrell case CTF_K_ENUM: 250*d876124dSJohn Birrell size += sizeof (ctf_enum_t) * vlen; 251*d876124dSJohn Birrell break; 252*d876124dSJohn Birrell } 253*d876124dSJohn Birrell } 254*d876124dSJohn Birrell 255*d876124dSJohn Birrell /* 256*d876124dSJohn Birrell * Fill in the string table offset and size, compute the size of the 257*d876124dSJohn Birrell * entire CTF buffer we need, and then allocate a new buffer and 258*d876124dSJohn Birrell * bcopy the finished header to the start of the buffer. 259*d876124dSJohn Birrell */ 260*d876124dSJohn Birrell hdr.cth_stroff = hdr.cth_typeoff + size; 261*d876124dSJohn Birrell hdr.cth_strlen = fp->ctf_dtstrlen; 262*d876124dSJohn Birrell size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; 263*d876124dSJohn Birrell 264*d876124dSJohn Birrell if ((buf = ctf_data_alloc(size)) == MAP_FAILED) 265*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 266*d876124dSJohn Birrell 267*d876124dSJohn Birrell bcopy(&hdr, buf, sizeof (ctf_header_t)); 268*d876124dSJohn Birrell t = (uchar_t *)buf + sizeof (ctf_header_t); 269*d876124dSJohn Birrell s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff; 270*d876124dSJohn Birrell 271*d876124dSJohn Birrell bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE)); 272*d876124dSJohn Birrell s += sizeof (_CTF_STRTAB_TEMPLATE); 273*d876124dSJohn Birrell 274*d876124dSJohn Birrell /* 275*d876124dSJohn Birrell * We now take a final lap through the dynamic type definition list and 276*d876124dSJohn Birrell * copy the appropriate type records and strings to the output buffer. 277*d876124dSJohn Birrell */ 278*d876124dSJohn Birrell for (dtd = ctf_list_next(&fp->ctf_dtdefs); 279*d876124dSJohn Birrell dtd != NULL; dtd = ctf_list_next(dtd)) { 280*d876124dSJohn Birrell 281*d876124dSJohn Birrell uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 282*d876124dSJohn Birrell uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 283*d876124dSJohn Birrell 284*d876124dSJohn Birrell ctf_array_t cta; 285*d876124dSJohn Birrell uint_t encoding; 286*d876124dSJohn Birrell size_t len; 287*d876124dSJohn Birrell 288*d876124dSJohn Birrell if (dtd->dtd_name != NULL) { 289*d876124dSJohn Birrell dtd->dtd_data.ctt_name = (uint_t)(s - s0); 290*d876124dSJohn Birrell len = strlen(dtd->dtd_name) + 1; 291*d876124dSJohn Birrell bcopy(dtd->dtd_name, s, len); 292*d876124dSJohn Birrell s += len; 293*d876124dSJohn Birrell } else 294*d876124dSJohn Birrell dtd->dtd_data.ctt_name = 0; 295*d876124dSJohn Birrell 296*d876124dSJohn Birrell if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) 297*d876124dSJohn Birrell len = sizeof (ctf_stype_t); 298*d876124dSJohn Birrell else 299*d876124dSJohn Birrell len = sizeof (ctf_type_t); 300*d876124dSJohn Birrell 301*d876124dSJohn Birrell bcopy(&dtd->dtd_data, t, len); 302*d876124dSJohn Birrell t += len; 303*d876124dSJohn Birrell 304*d876124dSJohn Birrell switch (kind) { 305*d876124dSJohn Birrell case CTF_K_INTEGER: 306*d876124dSJohn Birrell case CTF_K_FLOAT: 307*d876124dSJohn Birrell if (kind == CTF_K_INTEGER) { 308*d876124dSJohn Birrell encoding = CTF_INT_DATA( 309*d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_format, 310*d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_offset, 311*d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_bits); 312*d876124dSJohn Birrell } else { 313*d876124dSJohn Birrell encoding = CTF_FP_DATA( 314*d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_format, 315*d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_offset, 316*d876124dSJohn Birrell dtd->dtd_u.dtu_enc.cte_bits); 317*d876124dSJohn Birrell } 318*d876124dSJohn Birrell bcopy(&encoding, t, sizeof (encoding)); 319*d876124dSJohn Birrell t += sizeof (encoding); 320*d876124dSJohn Birrell break; 321*d876124dSJohn Birrell 322*d876124dSJohn Birrell case CTF_K_ARRAY: 323*d876124dSJohn Birrell cta.cta_contents = (ushort_t) 324*d876124dSJohn Birrell dtd->dtd_u.dtu_arr.ctr_contents; 325*d876124dSJohn Birrell cta.cta_index = (ushort_t) 326*d876124dSJohn Birrell dtd->dtd_u.dtu_arr.ctr_index; 327*d876124dSJohn Birrell cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; 328*d876124dSJohn Birrell bcopy(&cta, t, sizeof (cta)); 329*d876124dSJohn Birrell t += sizeof (cta); 330*d876124dSJohn Birrell break; 331*d876124dSJohn Birrell 332*d876124dSJohn Birrell case CTF_K_FUNCTION: { 333*d876124dSJohn Birrell ushort_t *argv = (ushort_t *)(uintptr_t)t; 334*d876124dSJohn Birrell uint_t argc; 335*d876124dSJohn Birrell 336*d876124dSJohn Birrell for (argc = 0; argc < vlen; argc++) 337*d876124dSJohn Birrell *argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc]; 338*d876124dSJohn Birrell 339*d876124dSJohn Birrell if (vlen & 1) 340*d876124dSJohn Birrell *argv++ = 0; /* pad to 4-byte boundary */ 341*d876124dSJohn Birrell 342*d876124dSJohn Birrell t = (uchar_t *)argv; 343*d876124dSJohn Birrell break; 344*d876124dSJohn Birrell } 345*d876124dSJohn Birrell 346*d876124dSJohn Birrell case CTF_K_STRUCT: 347*d876124dSJohn Birrell case CTF_K_UNION: 348*d876124dSJohn Birrell if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) 349*d876124dSJohn Birrell t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t); 350*d876124dSJohn Birrell else 351*d876124dSJohn Birrell t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t); 352*d876124dSJohn Birrell s = ctf_copy_membnames(dtd, s); 353*d876124dSJohn Birrell break; 354*d876124dSJohn Birrell 355*d876124dSJohn Birrell case CTF_K_ENUM: 356*d876124dSJohn Birrell t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t); 357*d876124dSJohn Birrell s = ctf_copy_membnames(dtd, s); 358*d876124dSJohn Birrell break; 359*d876124dSJohn Birrell } 360*d876124dSJohn Birrell } 361*d876124dSJohn Birrell 362*d876124dSJohn Birrell /* 363*d876124dSJohn Birrell * Finally, we are ready to ctf_bufopen() the new container. If this 364*d876124dSJohn Birrell * is successful, we then switch nfp and fp and free the old container. 365*d876124dSJohn Birrell */ 366*d876124dSJohn Birrell ctf_data_protect(buf, size); 367*d876124dSJohn Birrell cts.cts_name = _CTF_SECTION; 368*d876124dSJohn Birrell cts.cts_type = SHT_PROGBITS; 369*d876124dSJohn Birrell cts.cts_flags = 0; 370*d876124dSJohn Birrell cts.cts_data = buf; 371*d876124dSJohn Birrell cts.cts_size = size; 372*d876124dSJohn Birrell cts.cts_entsize = 1; 373*d876124dSJohn Birrell cts.cts_offset = 0; 374*d876124dSJohn Birrell 375*d876124dSJohn Birrell if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) { 376*d876124dSJohn Birrell ctf_data_free(buf, size); 377*d876124dSJohn Birrell return (ctf_set_errno(fp, err)); 378*d876124dSJohn Birrell } 379*d876124dSJohn Birrell 380*d876124dSJohn Birrell (void) ctf_setmodel(nfp, ctf_getmodel(fp)); 381*d876124dSJohn Birrell (void) ctf_import(nfp, fp->ctf_parent); 382*d876124dSJohn Birrell 383*d876124dSJohn Birrell nfp->ctf_refcnt = fp->ctf_refcnt; 384*d876124dSJohn Birrell nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY; 385*d876124dSJohn Birrell nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */ 386*d876124dSJohn Birrell nfp->ctf_dthash = fp->ctf_dthash; 387*d876124dSJohn Birrell nfp->ctf_dthashlen = fp->ctf_dthashlen; 388*d876124dSJohn Birrell nfp->ctf_dtdefs = fp->ctf_dtdefs; 389*d876124dSJohn Birrell nfp->ctf_dtstrlen = fp->ctf_dtstrlen; 390*d876124dSJohn Birrell nfp->ctf_dtnextid = fp->ctf_dtnextid; 391*d876124dSJohn Birrell nfp->ctf_dtoldid = fp->ctf_dtnextid - 1; 392*d876124dSJohn Birrell nfp->ctf_specific = fp->ctf_specific; 393*d876124dSJohn Birrell 394*d876124dSJohn Birrell fp->ctf_dthash = NULL; 395*d876124dSJohn Birrell fp->ctf_dthashlen = 0; 396*d876124dSJohn Birrell bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t)); 397*d876124dSJohn Birrell 398*d876124dSJohn Birrell bcopy(fp, &ofp, sizeof (ctf_file_t)); 399*d876124dSJohn Birrell bcopy(nfp, fp, sizeof (ctf_file_t)); 400*d876124dSJohn Birrell bcopy(&ofp, nfp, sizeof (ctf_file_t)); 401*d876124dSJohn Birrell 402*d876124dSJohn Birrell /* 403*d876124dSJohn Birrell * Initialize the ctf_lookup_by_name top-level dictionary. We keep an 404*d876124dSJohn Birrell * array of type name prefixes and the corresponding ctf_hash to use. 405*d876124dSJohn Birrell * NOTE: This code must be kept in sync with the code in ctf_bufopen(). 406*d876124dSJohn Birrell */ 407*d876124dSJohn Birrell fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; 408*d876124dSJohn Birrell fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; 409*d876124dSJohn Birrell fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; 410*d876124dSJohn Birrell fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; 411*d876124dSJohn Birrell 412*d876124dSJohn Birrell nfp->ctf_refcnt = 1; /* force nfp to be freed */ 413*d876124dSJohn Birrell ctf_close(nfp); 414*d876124dSJohn Birrell 415*d876124dSJohn Birrell return (0); 416*d876124dSJohn Birrell } 417*d876124dSJohn Birrell 418*d876124dSJohn Birrell void 419*d876124dSJohn Birrell ctf_dtd_insert(ctf_file_t *fp, ctf_dtdef_t *dtd) 420*d876124dSJohn Birrell { 421*d876124dSJohn Birrell ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); 422*d876124dSJohn Birrell 423*d876124dSJohn Birrell dtd->dtd_hash = fp->ctf_dthash[h]; 424*d876124dSJohn Birrell fp->ctf_dthash[h] = dtd; 425*d876124dSJohn Birrell ctf_list_append(&fp->ctf_dtdefs, dtd); 426*d876124dSJohn Birrell } 427*d876124dSJohn Birrell 428*d876124dSJohn Birrell void 429*d876124dSJohn Birrell ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) 430*d876124dSJohn Birrell { 431*d876124dSJohn Birrell ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); 432*d876124dSJohn Birrell ctf_dtdef_t *p, **q = &fp->ctf_dthash[h]; 433*d876124dSJohn Birrell ctf_dmdef_t *dmd, *nmd; 434*d876124dSJohn Birrell size_t len; 435*d876124dSJohn Birrell 436*d876124dSJohn Birrell for (p = *q; p != NULL; p = p->dtd_hash) { 437*d876124dSJohn Birrell if (p != dtd) 438*d876124dSJohn Birrell q = &p->dtd_hash; 439*d876124dSJohn Birrell else 440*d876124dSJohn Birrell break; 441*d876124dSJohn Birrell } 442*d876124dSJohn Birrell 443*d876124dSJohn Birrell if (p != NULL) 444*d876124dSJohn Birrell *q = p->dtd_hash; 445*d876124dSJohn Birrell 446*d876124dSJohn Birrell switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) { 447*d876124dSJohn Birrell case CTF_K_STRUCT: 448*d876124dSJohn Birrell case CTF_K_UNION: 449*d876124dSJohn Birrell case CTF_K_ENUM: 450*d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 451*d876124dSJohn Birrell dmd != NULL; dmd = nmd) { 452*d876124dSJohn Birrell if (dmd->dmd_name != NULL) { 453*d876124dSJohn Birrell len = strlen(dmd->dmd_name) + 1; 454*d876124dSJohn Birrell ctf_free(dmd->dmd_name, len); 455*d876124dSJohn Birrell fp->ctf_dtstrlen -= len; 456*d876124dSJohn Birrell } 457*d876124dSJohn Birrell nmd = ctf_list_next(dmd); 458*d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 459*d876124dSJohn Birrell } 460*d876124dSJohn Birrell break; 461*d876124dSJohn Birrell case CTF_K_FUNCTION: 462*d876124dSJohn Birrell ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * 463*d876124dSJohn Birrell CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); 464*d876124dSJohn Birrell break; 465*d876124dSJohn Birrell } 466*d876124dSJohn Birrell 467*d876124dSJohn Birrell if (dtd->dtd_name) { 468*d876124dSJohn Birrell len = strlen(dtd->dtd_name) + 1; 469*d876124dSJohn Birrell ctf_free(dtd->dtd_name, len); 470*d876124dSJohn Birrell fp->ctf_dtstrlen -= len; 471*d876124dSJohn Birrell } 472*d876124dSJohn Birrell 473*d876124dSJohn Birrell ctf_list_delete(&fp->ctf_dtdefs, dtd); 474*d876124dSJohn Birrell ctf_free(dtd, sizeof (ctf_dtdef_t)); 475*d876124dSJohn Birrell } 476*d876124dSJohn Birrell 477*d876124dSJohn Birrell ctf_dtdef_t * 478*d876124dSJohn Birrell ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) 479*d876124dSJohn Birrell { 480*d876124dSJohn Birrell ulong_t h = type & (fp->ctf_dthashlen - 1); 481*d876124dSJohn Birrell ctf_dtdef_t *dtd; 482*d876124dSJohn Birrell 483*d876124dSJohn Birrell if (fp->ctf_dthash == NULL) 484*d876124dSJohn Birrell return (NULL); 485*d876124dSJohn Birrell 486*d876124dSJohn Birrell for (dtd = fp->ctf_dthash[h]; dtd != NULL; dtd = dtd->dtd_hash) { 487*d876124dSJohn Birrell if (dtd->dtd_type == type) 488*d876124dSJohn Birrell break; 489*d876124dSJohn Birrell } 490*d876124dSJohn Birrell 491*d876124dSJohn Birrell return (dtd); 492*d876124dSJohn Birrell } 493*d876124dSJohn Birrell 494*d876124dSJohn Birrell /* 495*d876124dSJohn Birrell * Discard all of the dynamic type definitions that have been added to the 496*d876124dSJohn Birrell * container since the last call to ctf_update(). We locate such types by 497*d876124dSJohn Birrell * scanning the list and deleting elements that have type IDs greater than 498*d876124dSJohn Birrell * ctf_dtoldid, which is set by ctf_update(), above. 499*d876124dSJohn Birrell */ 500*d876124dSJohn Birrell int 501*d876124dSJohn Birrell ctf_discard(ctf_file_t *fp) 502*d876124dSJohn Birrell { 503*d876124dSJohn Birrell ctf_dtdef_t *dtd, *ntd; 504*d876124dSJohn Birrell 505*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 506*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 507*d876124dSJohn Birrell 508*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_DIRTY)) 509*d876124dSJohn Birrell return (0); /* no update required */ 510*d876124dSJohn Birrell 511*d876124dSJohn Birrell for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { 512*d876124dSJohn Birrell if (dtd->dtd_type <= fp->ctf_dtoldid) 513*d876124dSJohn Birrell continue; /* skip types that have been committed */ 514*d876124dSJohn Birrell 515*d876124dSJohn Birrell ntd = ctf_list_next(dtd); 516*d876124dSJohn Birrell ctf_dtd_delete(fp, dtd); 517*d876124dSJohn Birrell } 518*d876124dSJohn Birrell 519*d876124dSJohn Birrell fp->ctf_dtnextid = fp->ctf_dtoldid + 1; 520*d876124dSJohn Birrell fp->ctf_flags &= ~LCTF_DIRTY; 521*d876124dSJohn Birrell 522*d876124dSJohn Birrell return (0); 523*d876124dSJohn Birrell } 524*d876124dSJohn Birrell 525*d876124dSJohn Birrell static ctf_id_t 526*d876124dSJohn Birrell ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp) 527*d876124dSJohn Birrell { 528*d876124dSJohn Birrell ctf_dtdef_t *dtd; 529*d876124dSJohn Birrell ctf_id_t type; 530*d876124dSJohn Birrell char *s = NULL; 531*d876124dSJohn Birrell 532*d876124dSJohn Birrell if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT) 533*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 534*d876124dSJohn Birrell 535*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 536*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 537*d876124dSJohn Birrell 538*d876124dSJohn Birrell if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE) 539*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_FULL)); 540*d876124dSJohn Birrell 541*d876124dSJohn Birrell if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL) 542*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 543*d876124dSJohn Birrell 544*d876124dSJohn Birrell if (name != NULL && (s = ctf_strdup(name)) == NULL) { 545*d876124dSJohn Birrell ctf_free(dtd, sizeof (ctf_dtdef_t)); 546*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 547*d876124dSJohn Birrell } 548*d876124dSJohn Birrell 549*d876124dSJohn Birrell type = fp->ctf_dtnextid++; 550*d876124dSJohn Birrell type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD)); 551*d876124dSJohn Birrell 552*d876124dSJohn Birrell bzero(dtd, sizeof (ctf_dtdef_t)); 553*d876124dSJohn Birrell dtd->dtd_name = s; 554*d876124dSJohn Birrell dtd->dtd_type = type; 555*d876124dSJohn Birrell 556*d876124dSJohn Birrell if (s != NULL) 557*d876124dSJohn Birrell fp->ctf_dtstrlen += strlen(s) + 1; 558*d876124dSJohn Birrell 559*d876124dSJohn Birrell ctf_dtd_insert(fp, dtd); 560*d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 561*d876124dSJohn Birrell 562*d876124dSJohn Birrell *rp = dtd; 563*d876124dSJohn Birrell return (type); 564*d876124dSJohn Birrell } 565*d876124dSJohn Birrell 566*d876124dSJohn Birrell /* 567*d876124dSJohn Birrell * When encoding integer sizes, we want to convert a byte count in the range 568*d876124dSJohn Birrell * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function 569*d876124dSJohn Birrell * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. 570*d876124dSJohn Birrell */ 571*d876124dSJohn Birrell static size_t 572*d876124dSJohn Birrell clp2(size_t x) 573*d876124dSJohn Birrell { 574*d876124dSJohn Birrell x--; 575*d876124dSJohn Birrell 576*d876124dSJohn Birrell x |= (x >> 1); 577*d876124dSJohn Birrell x |= (x >> 2); 578*d876124dSJohn Birrell x |= (x >> 4); 579*d876124dSJohn Birrell x |= (x >> 8); 580*d876124dSJohn Birrell x |= (x >> 16); 581*d876124dSJohn Birrell 582*d876124dSJohn Birrell return (x + 1); 583*d876124dSJohn Birrell } 584*d876124dSJohn Birrell 585*d876124dSJohn Birrell static ctf_id_t 586*d876124dSJohn Birrell ctf_add_encoded(ctf_file_t *fp, uint_t flag, 587*d876124dSJohn Birrell const char *name, const ctf_encoding_t *ep, uint_t kind) 588*d876124dSJohn Birrell { 589*d876124dSJohn Birrell ctf_dtdef_t *dtd; 590*d876124dSJohn Birrell ctf_id_t type; 591*d876124dSJohn Birrell 592*d876124dSJohn Birrell if (ep == NULL) 593*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 594*d876124dSJohn Birrell 595*d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 596*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 597*d876124dSJohn Birrell 598*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); 599*d876124dSJohn Birrell dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY); 600*d876124dSJohn Birrell dtd->dtd_u.dtu_enc = *ep; 601*d876124dSJohn Birrell 602*d876124dSJohn Birrell return (type); 603*d876124dSJohn Birrell } 604*d876124dSJohn Birrell 605*d876124dSJohn Birrell static ctf_id_t 606*d876124dSJohn Birrell ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind) 607*d876124dSJohn Birrell { 608*d876124dSJohn Birrell ctf_dtdef_t *dtd; 609*d876124dSJohn Birrell ctf_id_t type; 610*d876124dSJohn Birrell 611*d876124dSJohn Birrell if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) 612*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 613*d876124dSJohn Birrell 614*d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) 615*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 616*d876124dSJohn Birrell 617*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); 618*d876124dSJohn Birrell dtd->dtd_data.ctt_type = (ushort_t)ref; 619*d876124dSJohn Birrell 620*d876124dSJohn Birrell return (type); 621*d876124dSJohn Birrell } 622*d876124dSJohn Birrell 623*d876124dSJohn Birrell ctf_id_t 624*d876124dSJohn Birrell ctf_add_integer(ctf_file_t *fp, uint_t flag, 625*d876124dSJohn Birrell const char *name, const ctf_encoding_t *ep) 626*d876124dSJohn Birrell { 627*d876124dSJohn Birrell return (ctf_add_encoded(fp, flag, name, ep, CTF_K_INTEGER)); 628*d876124dSJohn Birrell } 629*d876124dSJohn Birrell 630*d876124dSJohn Birrell ctf_id_t 631*d876124dSJohn Birrell ctf_add_float(ctf_file_t *fp, uint_t flag, 632*d876124dSJohn Birrell const char *name, const ctf_encoding_t *ep) 633*d876124dSJohn Birrell { 634*d876124dSJohn Birrell return (ctf_add_encoded(fp, flag, name, ep, CTF_K_FLOAT)); 635*d876124dSJohn Birrell } 636*d876124dSJohn Birrell 637*d876124dSJohn Birrell ctf_id_t 638*d876124dSJohn Birrell ctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 639*d876124dSJohn Birrell { 640*d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER)); 641*d876124dSJohn Birrell } 642*d876124dSJohn Birrell 643*d876124dSJohn Birrell ctf_id_t 644*d876124dSJohn Birrell ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) 645*d876124dSJohn Birrell { 646*d876124dSJohn Birrell ctf_dtdef_t *dtd; 647*d876124dSJohn Birrell ctf_id_t type; 648*d876124dSJohn Birrell 649*d876124dSJohn Birrell if (arp == NULL) 650*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 651*d876124dSJohn Birrell 652*d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) 653*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 654*d876124dSJohn Birrell 655*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); 656*d876124dSJohn Birrell dtd->dtd_data.ctt_size = 0; 657*d876124dSJohn Birrell dtd->dtd_u.dtu_arr = *arp; 658*d876124dSJohn Birrell 659*d876124dSJohn Birrell return (type); 660*d876124dSJohn Birrell } 661*d876124dSJohn Birrell 662*d876124dSJohn Birrell int 663*d876124dSJohn Birrell ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) 664*d876124dSJohn Birrell { 665*d876124dSJohn Birrell ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); 666*d876124dSJohn Birrell 667*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 668*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 669*d876124dSJohn Birrell 670*d876124dSJohn Birrell if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) 671*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_BADID)); 672*d876124dSJohn Birrell 673*d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 674*d876124dSJohn Birrell dtd->dtd_u.dtu_arr = *arp; 675*d876124dSJohn Birrell 676*d876124dSJohn Birrell return (0); 677*d876124dSJohn Birrell } 678*d876124dSJohn Birrell 679*d876124dSJohn Birrell ctf_id_t 680*d876124dSJohn Birrell ctf_add_function(ctf_file_t *fp, uint_t flag, 681*d876124dSJohn Birrell const ctf_funcinfo_t *ctc, const ctf_id_t *argv) 682*d876124dSJohn Birrell { 683*d876124dSJohn Birrell ctf_dtdef_t *dtd; 684*d876124dSJohn Birrell ctf_id_t type; 685*d876124dSJohn Birrell uint_t vlen; 686*d876124dSJohn Birrell ctf_id_t *vdat = NULL; 687*d876124dSJohn Birrell 688*d876124dSJohn Birrell if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || 689*d876124dSJohn Birrell (ctc->ctc_argc != 0 && argv == NULL)) 690*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 691*d876124dSJohn Birrell 692*d876124dSJohn Birrell vlen = ctc->ctc_argc; 693*d876124dSJohn Birrell if (ctc->ctc_flags & CTF_FUNC_VARARG) 694*d876124dSJohn Birrell vlen++; /* add trailing zero to indicate varargs (see below) */ 695*d876124dSJohn Birrell 696*d876124dSJohn Birrell if (vlen > CTF_MAX_VLEN) 697*d876124dSJohn Birrell return (ctf_set_errno(fp, EOVERFLOW)); 698*d876124dSJohn Birrell 699*d876124dSJohn Birrell if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) 700*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 701*d876124dSJohn Birrell 702*d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) { 703*d876124dSJohn Birrell ctf_free(vdat, sizeof (ctf_id_t) * vlen); 704*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 705*d876124dSJohn Birrell } 706*d876124dSJohn Birrell 707*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); 708*d876124dSJohn Birrell dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; 709*d876124dSJohn Birrell 710*d876124dSJohn Birrell bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); 711*d876124dSJohn Birrell if (ctc->ctc_flags & CTF_FUNC_VARARG) 712*d876124dSJohn Birrell vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ 713*d876124dSJohn Birrell dtd->dtd_u.dtu_argv = vdat; 714*d876124dSJohn Birrell 715*d876124dSJohn Birrell return (type); 716*d876124dSJohn Birrell } 717*d876124dSJohn Birrell 718*d876124dSJohn Birrell ctf_id_t 719*d876124dSJohn Birrell ctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name) 720*d876124dSJohn Birrell { 721*d876124dSJohn Birrell ctf_hash_t *hp = &fp->ctf_structs; 722*d876124dSJohn Birrell ctf_helem_t *hep = NULL; 723*d876124dSJohn Birrell ctf_dtdef_t *dtd; 724*d876124dSJohn Birrell ctf_id_t type; 725*d876124dSJohn Birrell 726*d876124dSJohn Birrell if (name != NULL) 727*d876124dSJohn Birrell hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 728*d876124dSJohn Birrell 729*d876124dSJohn Birrell if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 730*d876124dSJohn Birrell dtd = ctf_dtd_lookup(fp, type = hep->h_type); 731*d876124dSJohn Birrell else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 732*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 733*d876124dSJohn Birrell 734*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0); 735*d876124dSJohn Birrell dtd->dtd_data.ctt_size = 0; 736*d876124dSJohn Birrell 737*d876124dSJohn Birrell return (type); 738*d876124dSJohn Birrell } 739*d876124dSJohn Birrell 740*d876124dSJohn Birrell ctf_id_t 741*d876124dSJohn Birrell ctf_add_union(ctf_file_t *fp, uint_t flag, const char *name) 742*d876124dSJohn Birrell { 743*d876124dSJohn Birrell ctf_hash_t *hp = &fp->ctf_unions; 744*d876124dSJohn Birrell ctf_helem_t *hep = NULL; 745*d876124dSJohn Birrell ctf_dtdef_t *dtd; 746*d876124dSJohn Birrell ctf_id_t type; 747*d876124dSJohn Birrell 748*d876124dSJohn Birrell if (name != NULL) 749*d876124dSJohn Birrell hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 750*d876124dSJohn Birrell 751*d876124dSJohn Birrell if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 752*d876124dSJohn Birrell dtd = ctf_dtd_lookup(fp, type = hep->h_type); 753*d876124dSJohn Birrell else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 754*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 755*d876124dSJohn Birrell 756*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0); 757*d876124dSJohn Birrell dtd->dtd_data.ctt_size = 0; 758*d876124dSJohn Birrell 759*d876124dSJohn Birrell return (type); 760*d876124dSJohn Birrell } 761*d876124dSJohn Birrell 762*d876124dSJohn Birrell ctf_id_t 763*d876124dSJohn Birrell ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name) 764*d876124dSJohn Birrell { 765*d876124dSJohn Birrell ctf_hash_t *hp = &fp->ctf_enums; 766*d876124dSJohn Birrell ctf_helem_t *hep = NULL; 767*d876124dSJohn Birrell ctf_dtdef_t *dtd; 768*d876124dSJohn Birrell ctf_id_t type; 769*d876124dSJohn Birrell 770*d876124dSJohn Birrell if (name != NULL) 771*d876124dSJohn Birrell hep = ctf_hash_lookup(hp, fp, name, strlen(name)); 772*d876124dSJohn Birrell 773*d876124dSJohn Birrell if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) 774*d876124dSJohn Birrell dtd = ctf_dtd_lookup(fp, type = hep->h_type); 775*d876124dSJohn Birrell else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 776*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 777*d876124dSJohn Birrell 778*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0); 779*d876124dSJohn Birrell dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int; 780*d876124dSJohn Birrell 781*d876124dSJohn Birrell return (type); 782*d876124dSJohn Birrell } 783*d876124dSJohn Birrell 784*d876124dSJohn Birrell ctf_id_t 785*d876124dSJohn Birrell ctf_add_forward(ctf_file_t *fp, uint_t flag, const char *name, uint_t kind) 786*d876124dSJohn Birrell { 787*d876124dSJohn Birrell ctf_hash_t *hp; 788*d876124dSJohn Birrell ctf_helem_t *hep; 789*d876124dSJohn Birrell ctf_dtdef_t *dtd; 790*d876124dSJohn Birrell ctf_id_t type; 791*d876124dSJohn Birrell 792*d876124dSJohn Birrell switch (kind) { 793*d876124dSJohn Birrell case CTF_K_STRUCT: 794*d876124dSJohn Birrell hp = &fp->ctf_structs; 795*d876124dSJohn Birrell break; 796*d876124dSJohn Birrell case CTF_K_UNION: 797*d876124dSJohn Birrell hp = &fp->ctf_unions; 798*d876124dSJohn Birrell break; 799*d876124dSJohn Birrell case CTF_K_ENUM: 800*d876124dSJohn Birrell hp = &fp->ctf_enums; 801*d876124dSJohn Birrell break; 802*d876124dSJohn Birrell default: 803*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_NOTSUE)); 804*d876124dSJohn Birrell } 805*d876124dSJohn Birrell 806*d876124dSJohn Birrell /* 807*d876124dSJohn Birrell * If the type is already defined or exists as a forward tag, just 808*d876124dSJohn Birrell * return the ctf_id_t of the existing definition. 809*d876124dSJohn Birrell */ 810*d876124dSJohn Birrell if (name != NULL && (hep = ctf_hash_lookup(hp, 811*d876124dSJohn Birrell fp, name, strlen(name))) != NULL) 812*d876124dSJohn Birrell return (hep->h_type); 813*d876124dSJohn Birrell 814*d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 815*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 816*d876124dSJohn Birrell 817*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, flag, 0); 818*d876124dSJohn Birrell dtd->dtd_data.ctt_type = kind; 819*d876124dSJohn Birrell 820*d876124dSJohn Birrell return (type); 821*d876124dSJohn Birrell } 822*d876124dSJohn Birrell 823*d876124dSJohn Birrell ctf_id_t 824*d876124dSJohn Birrell ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) 825*d876124dSJohn Birrell { 826*d876124dSJohn Birrell ctf_dtdef_t *dtd; 827*d876124dSJohn Birrell ctf_id_t type; 828*d876124dSJohn Birrell 829*d876124dSJohn Birrell if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) 830*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 831*d876124dSJohn Birrell 832*d876124dSJohn Birrell if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) 833*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 834*d876124dSJohn Birrell 835*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); 836*d876124dSJohn Birrell dtd->dtd_data.ctt_type = (ushort_t)ref; 837*d876124dSJohn Birrell 838*d876124dSJohn Birrell return (type); 839*d876124dSJohn Birrell } 840*d876124dSJohn Birrell 841*d876124dSJohn Birrell ctf_id_t 842*d876124dSJohn Birrell ctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 843*d876124dSJohn Birrell { 844*d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE)); 845*d876124dSJohn Birrell } 846*d876124dSJohn Birrell 847*d876124dSJohn Birrell ctf_id_t 848*d876124dSJohn Birrell ctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 849*d876124dSJohn Birrell { 850*d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST)); 851*d876124dSJohn Birrell } 852*d876124dSJohn Birrell 853*d876124dSJohn Birrell ctf_id_t 854*d876124dSJohn Birrell ctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref) 855*d876124dSJohn Birrell { 856*d876124dSJohn Birrell return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT)); 857*d876124dSJohn Birrell } 858*d876124dSJohn Birrell 859*d876124dSJohn Birrell int 860*d876124dSJohn Birrell ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value) 861*d876124dSJohn Birrell { 862*d876124dSJohn Birrell ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid); 863*d876124dSJohn Birrell ctf_dmdef_t *dmd; 864*d876124dSJohn Birrell 865*d876124dSJohn Birrell uint_t kind, vlen, root; 866*d876124dSJohn Birrell char *s; 867*d876124dSJohn Birrell 868*d876124dSJohn Birrell if (name == NULL) 869*d876124dSJohn Birrell return (ctf_set_errno(fp, EINVAL)); 870*d876124dSJohn Birrell 871*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 872*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 873*d876124dSJohn Birrell 874*d876124dSJohn Birrell if (dtd == NULL) 875*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_BADID)); 876*d876124dSJohn Birrell 877*d876124dSJohn Birrell kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 878*d876124dSJohn Birrell root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); 879*d876124dSJohn Birrell vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 880*d876124dSJohn Birrell 881*d876124dSJohn Birrell if (kind != CTF_K_ENUM) 882*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_NOTENUM)); 883*d876124dSJohn Birrell 884*d876124dSJohn Birrell if (vlen == CTF_MAX_VLEN) 885*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DTFULL)); 886*d876124dSJohn Birrell 887*d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 888*d876124dSJohn Birrell dmd != NULL; dmd = ctf_list_next(dmd)) { 889*d876124dSJohn Birrell if (strcmp(dmd->dmd_name, name) == 0) 890*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DUPMEMBER)); 891*d876124dSJohn Birrell } 892*d876124dSJohn Birrell 893*d876124dSJohn Birrell if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 894*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 895*d876124dSJohn Birrell 896*d876124dSJohn Birrell if ((s = ctf_strdup(name)) == NULL) { 897*d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 898*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 899*d876124dSJohn Birrell } 900*d876124dSJohn Birrell 901*d876124dSJohn Birrell dmd->dmd_name = s; 902*d876124dSJohn Birrell dmd->dmd_type = CTF_ERR; 903*d876124dSJohn Birrell dmd->dmd_offset = 0; 904*d876124dSJohn Birrell dmd->dmd_value = value; 905*d876124dSJohn Birrell 906*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); 907*d876124dSJohn Birrell ctf_list_append(&dtd->dtd_u.dtu_members, dmd); 908*d876124dSJohn Birrell 909*d876124dSJohn Birrell fp->ctf_dtstrlen += strlen(s) + 1; 910*d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 911*d876124dSJohn Birrell 912*d876124dSJohn Birrell return (0); 913*d876124dSJohn Birrell } 914*d876124dSJohn Birrell 915*d876124dSJohn Birrell int 916*d876124dSJohn Birrell ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) 917*d876124dSJohn Birrell { 918*d876124dSJohn Birrell ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid); 919*d876124dSJohn Birrell ctf_dmdef_t *dmd; 920*d876124dSJohn Birrell 921*d876124dSJohn Birrell ssize_t msize, malign, ssize; 922*d876124dSJohn Birrell uint_t kind, vlen, root; 923*d876124dSJohn Birrell char *s = NULL; 924*d876124dSJohn Birrell 925*d876124dSJohn Birrell if (!(fp->ctf_flags & LCTF_RDWR)) 926*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_RDONLY)); 927*d876124dSJohn Birrell 928*d876124dSJohn Birrell if (dtd == NULL) 929*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_BADID)); 930*d876124dSJohn Birrell 931*d876124dSJohn Birrell kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); 932*d876124dSJohn Birrell root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); 933*d876124dSJohn Birrell vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); 934*d876124dSJohn Birrell 935*d876124dSJohn Birrell if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 936*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_NOTSOU)); 937*d876124dSJohn Birrell 938*d876124dSJohn Birrell if (vlen == CTF_MAX_VLEN) 939*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DTFULL)); 940*d876124dSJohn Birrell 941*d876124dSJohn Birrell if (name != NULL) { 942*d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 943*d876124dSJohn Birrell dmd != NULL; dmd = ctf_list_next(dmd)) { 944*d876124dSJohn Birrell if (dmd->dmd_name != NULL && 945*d876124dSJohn Birrell strcmp(dmd->dmd_name, name) == 0) 946*d876124dSJohn Birrell return (ctf_set_errno(fp, ECTF_DUPMEMBER)); 947*d876124dSJohn Birrell } 948*d876124dSJohn Birrell } 949*d876124dSJohn Birrell 950*d876124dSJohn Birrell if ((msize = ctf_type_size(fp, type)) == CTF_ERR || 951*d876124dSJohn Birrell (malign = ctf_type_align(fp, type)) == CTF_ERR) 952*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 953*d876124dSJohn Birrell 954*d876124dSJohn Birrell if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 955*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 956*d876124dSJohn Birrell 957*d876124dSJohn Birrell if (name != NULL && (s = ctf_strdup(name)) == NULL) { 958*d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 959*d876124dSJohn Birrell return (ctf_set_errno(fp, EAGAIN)); 960*d876124dSJohn Birrell } 961*d876124dSJohn Birrell 962*d876124dSJohn Birrell dmd->dmd_name = s; 963*d876124dSJohn Birrell dmd->dmd_type = type; 964*d876124dSJohn Birrell dmd->dmd_value = -1; 965*d876124dSJohn Birrell 966*d876124dSJohn Birrell if (kind == CTF_K_STRUCT && vlen != 0) { 967*d876124dSJohn Birrell ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members); 968*d876124dSJohn Birrell ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type); 969*d876124dSJohn Birrell size_t off = lmd->dmd_offset; 970*d876124dSJohn Birrell 971*d876124dSJohn Birrell ctf_encoding_t linfo; 972*d876124dSJohn Birrell ssize_t lsize; 973*d876124dSJohn Birrell 974*d876124dSJohn Birrell if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR) 975*d876124dSJohn Birrell off += linfo.cte_bits; 976*d876124dSJohn Birrell else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR) 977*d876124dSJohn Birrell off += lsize * NBBY; 978*d876124dSJohn Birrell 979*d876124dSJohn Birrell /* 980*d876124dSJohn Birrell * Round up the offset of the end of the last member to the 981*d876124dSJohn Birrell * next byte boundary, convert 'off' to bytes, and then round 982*d876124dSJohn Birrell * it up again to the next multiple of the alignment required 983*d876124dSJohn Birrell * by the new member. Finally, convert back to bits and store 984*d876124dSJohn Birrell * the result in dmd_offset. Technically we could do more 985*d876124dSJohn Birrell * efficient packing if the new member is a bit-field, but 986*d876124dSJohn Birrell * we're the "compiler" and ANSI says we can do as we choose. 987*d876124dSJohn Birrell */ 988*d876124dSJohn Birrell off = roundup(off, NBBY) / NBBY; 989*d876124dSJohn Birrell off = roundup(off, MAX(malign, 1)); 990*d876124dSJohn Birrell dmd->dmd_offset = off * NBBY; 991*d876124dSJohn Birrell ssize = off + msize; 992*d876124dSJohn Birrell } else { 993*d876124dSJohn Birrell dmd->dmd_offset = 0; 994*d876124dSJohn Birrell ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL); 995*d876124dSJohn Birrell ssize = MAX(ssize, msize); 996*d876124dSJohn Birrell } 997*d876124dSJohn Birrell 998*d876124dSJohn Birrell if (ssize > CTF_MAX_SIZE) { 999*d876124dSJohn Birrell dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; 1000*d876124dSJohn Birrell dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize); 1001*d876124dSJohn Birrell dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize); 1002*d876124dSJohn Birrell } else 1003*d876124dSJohn Birrell dtd->dtd_data.ctt_size = (ushort_t)ssize; 1004*d876124dSJohn Birrell 1005*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); 1006*d876124dSJohn Birrell ctf_list_append(&dtd->dtd_u.dtu_members, dmd); 1007*d876124dSJohn Birrell 1008*d876124dSJohn Birrell if (s != NULL) 1009*d876124dSJohn Birrell fp->ctf_dtstrlen += strlen(s) + 1; 1010*d876124dSJohn Birrell 1011*d876124dSJohn Birrell fp->ctf_flags |= LCTF_DIRTY; 1012*d876124dSJohn Birrell return (0); 1013*d876124dSJohn Birrell } 1014*d876124dSJohn Birrell 1015*d876124dSJohn Birrell static int 1016*d876124dSJohn Birrell enumcmp(const char *name, int value, void *arg) 1017*d876124dSJohn Birrell { 1018*d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1019*d876124dSJohn Birrell int bvalue; 1020*d876124dSJohn Birrell 1021*d876124dSJohn Birrell return (ctf_enum_value(ctb->ctb_file, ctb->ctb_type, 1022*d876124dSJohn Birrell name, &bvalue) == CTF_ERR || value != bvalue); 1023*d876124dSJohn Birrell } 1024*d876124dSJohn Birrell 1025*d876124dSJohn Birrell static int 1026*d876124dSJohn Birrell enumadd(const char *name, int value, void *arg) 1027*d876124dSJohn Birrell { 1028*d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1029*d876124dSJohn Birrell 1030*d876124dSJohn Birrell return (ctf_add_enumerator(ctb->ctb_file, ctb->ctb_type, 1031*d876124dSJohn Birrell name, value) == CTF_ERR); 1032*d876124dSJohn Birrell } 1033*d876124dSJohn Birrell 1034*d876124dSJohn Birrell /*ARGSUSED*/ 1035*d876124dSJohn Birrell static int 1036*d876124dSJohn Birrell membcmp(const char *name, ctf_id_t type, ulong_t offset, void *arg) 1037*d876124dSJohn Birrell { 1038*d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1039*d876124dSJohn Birrell ctf_membinfo_t ctm; 1040*d876124dSJohn Birrell 1041*d876124dSJohn Birrell return (ctf_member_info(ctb->ctb_file, ctb->ctb_type, 1042*d876124dSJohn Birrell name, &ctm) == CTF_ERR || ctm.ctm_offset != offset); 1043*d876124dSJohn Birrell } 1044*d876124dSJohn Birrell 1045*d876124dSJohn Birrell static int 1046*d876124dSJohn Birrell membadd(const char *name, ctf_id_t type, ulong_t offset, void *arg) 1047*d876124dSJohn Birrell { 1048*d876124dSJohn Birrell ctf_bundle_t *ctb = arg; 1049*d876124dSJohn Birrell ctf_dmdef_t *dmd; 1050*d876124dSJohn Birrell char *s = NULL; 1051*d876124dSJohn Birrell 1052*d876124dSJohn Birrell if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) 1053*d876124dSJohn Birrell return (ctf_set_errno(ctb->ctb_file, EAGAIN)); 1054*d876124dSJohn Birrell 1055*d876124dSJohn Birrell if (name != NULL && (s = ctf_strdup(name)) == NULL) { 1056*d876124dSJohn Birrell ctf_free(dmd, sizeof (ctf_dmdef_t)); 1057*d876124dSJohn Birrell return (ctf_set_errno(ctb->ctb_file, EAGAIN)); 1058*d876124dSJohn Birrell } 1059*d876124dSJohn Birrell 1060*d876124dSJohn Birrell /* 1061*d876124dSJohn Birrell * For now, dmd_type is copied as the src_fp's type; it is reset to an 1062*d876124dSJohn Birrell * equivalent dst_fp type by a final loop in ctf_add_type(), below. 1063*d876124dSJohn Birrell */ 1064*d876124dSJohn Birrell dmd->dmd_name = s; 1065*d876124dSJohn Birrell dmd->dmd_type = type; 1066*d876124dSJohn Birrell dmd->dmd_offset = offset; 1067*d876124dSJohn Birrell dmd->dmd_value = -1; 1068*d876124dSJohn Birrell 1069*d876124dSJohn Birrell ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd); 1070*d876124dSJohn Birrell 1071*d876124dSJohn Birrell if (s != NULL) 1072*d876124dSJohn Birrell ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1; 1073*d876124dSJohn Birrell 1074*d876124dSJohn Birrell ctb->ctb_file->ctf_flags |= LCTF_DIRTY; 1075*d876124dSJohn Birrell return (0); 1076*d876124dSJohn Birrell } 1077*d876124dSJohn Birrell 1078*d876124dSJohn Birrell /* 1079*d876124dSJohn Birrell * The ctf_add_type routine is used to copy a type from a source CTF container 1080*d876124dSJohn Birrell * to a dynamic destination container. This routine operates recursively by 1081*d876124dSJohn Birrell * following the source type's links and embedded member types. If the 1082*d876124dSJohn Birrell * destination container already contains a named type which has the same 1083*d876124dSJohn Birrell * attributes, then we succeed and return this type but no changes occur. 1084*d876124dSJohn Birrell */ 1085*d876124dSJohn Birrell ctf_id_t 1086*d876124dSJohn Birrell ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) 1087*d876124dSJohn Birrell { 1088*d876124dSJohn Birrell ctf_id_t dst_type = CTF_ERR; 1089*d876124dSJohn Birrell uint_t dst_kind = CTF_K_UNKNOWN; 1090*d876124dSJohn Birrell 1091*d876124dSJohn Birrell const ctf_type_t *tp; 1092*d876124dSJohn Birrell const char *name; 1093*d876124dSJohn Birrell uint_t kind, flag, vlen; 1094*d876124dSJohn Birrell 1095*d876124dSJohn Birrell ctf_bundle_t src, dst; 1096*d876124dSJohn Birrell ctf_encoding_t src_en, dst_en; 1097*d876124dSJohn Birrell ctf_arinfo_t src_ar, dst_ar; 1098*d876124dSJohn Birrell 1099*d876124dSJohn Birrell ctf_dtdef_t *dtd; 1100*d876124dSJohn Birrell ctf_funcinfo_t ctc; 1101*d876124dSJohn Birrell ssize_t size; 1102*d876124dSJohn Birrell 1103*d876124dSJohn Birrell ctf_hash_t *hp; 1104*d876124dSJohn Birrell ctf_helem_t *hep; 1105*d876124dSJohn Birrell 1106*d876124dSJohn Birrell if (!(dst_fp->ctf_flags & LCTF_RDWR)) 1107*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_RDONLY)); 1108*d876124dSJohn Birrell 1109*d876124dSJohn Birrell if ((tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL) 1110*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 1111*d876124dSJohn Birrell 1112*d876124dSJohn Birrell name = ctf_strptr(src_fp, tp->ctt_name); 1113*d876124dSJohn Birrell kind = LCTF_INFO_KIND(src_fp, tp->ctt_info); 1114*d876124dSJohn Birrell flag = LCTF_INFO_ROOT(src_fp, tp->ctt_info); 1115*d876124dSJohn Birrell vlen = LCTF_INFO_VLEN(src_fp, tp->ctt_info); 1116*d876124dSJohn Birrell 1117*d876124dSJohn Birrell switch (kind) { 1118*d876124dSJohn Birrell case CTF_K_STRUCT: 1119*d876124dSJohn Birrell hp = &dst_fp->ctf_structs; 1120*d876124dSJohn Birrell break; 1121*d876124dSJohn Birrell case CTF_K_UNION: 1122*d876124dSJohn Birrell hp = &dst_fp->ctf_unions; 1123*d876124dSJohn Birrell break; 1124*d876124dSJohn Birrell case CTF_K_ENUM: 1125*d876124dSJohn Birrell hp = &dst_fp->ctf_enums; 1126*d876124dSJohn Birrell break; 1127*d876124dSJohn Birrell default: 1128*d876124dSJohn Birrell hp = &dst_fp->ctf_names; 1129*d876124dSJohn Birrell break; 1130*d876124dSJohn Birrell } 1131*d876124dSJohn Birrell 1132*d876124dSJohn Birrell /* 1133*d876124dSJohn Birrell * If the source type has a name and is a root type (visible at the 1134*d876124dSJohn Birrell * top-level scope), lookup the name in the destination container and 1135*d876124dSJohn Birrell * verify that it is of the same kind before we do anything else. 1136*d876124dSJohn Birrell */ 1137*d876124dSJohn Birrell if ((flag & CTF_ADD_ROOT) && name[0] != '\0' && 1138*d876124dSJohn Birrell (hep = ctf_hash_lookup(hp, dst_fp, name, strlen(name))) != NULL) { 1139*d876124dSJohn Birrell dst_type = (ctf_id_t)hep->h_type; 1140*d876124dSJohn Birrell dst_kind = ctf_type_kind(dst_fp, dst_type); 1141*d876124dSJohn Birrell } 1142*d876124dSJohn Birrell 1143*d876124dSJohn Birrell /* 1144*d876124dSJohn Birrell * If an identically named dst_type exists, fail with ECTF_CONFLICT 1145*d876124dSJohn Birrell * unless dst_type is a forward declaration and src_type is a struct, 1146*d876124dSJohn Birrell * union, or enum (i.e. the definition of the previous forward decl). 1147*d876124dSJohn Birrell */ 1148*d876124dSJohn Birrell if (dst_type != CTF_ERR && dst_kind != kind && ( 1149*d876124dSJohn Birrell dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM && 1150*d876124dSJohn Birrell kind != CTF_K_STRUCT && kind != CTF_K_UNION))) 1151*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1152*d876124dSJohn Birrell 1153*d876124dSJohn Birrell /* 1154*d876124dSJohn Birrell * If the non-empty name was not found in the appropriate hash, search 1155*d876124dSJohn Birrell * the list of pending dynamic definitions that are not yet committed. 1156*d876124dSJohn Birrell * If a matching name and kind are found, assume this is the type that 1157*d876124dSJohn Birrell * we are looking for. This is necessary to permit ctf_add_type() to 1158*d876124dSJohn Birrell * operate recursively on entities such as a struct that contains a 1159*d876124dSJohn Birrell * pointer member that refers to the same struct type. 1160*d876124dSJohn Birrell */ 1161*d876124dSJohn Birrell if (dst_type == CTF_ERR && name[0] != '\0') { 1162*d876124dSJohn Birrell for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL && 1163*d876124dSJohn Birrell dtd->dtd_type > dst_fp->ctf_dtoldid; 1164*d876124dSJohn Birrell dtd = ctf_list_prev(dtd)) { 1165*d876124dSJohn Birrell if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) == kind && 1166*d876124dSJohn Birrell dtd->dtd_name != NULL && 1167*d876124dSJohn Birrell strcmp(dtd->dtd_name, name) == 0) 1168*d876124dSJohn Birrell return (dtd->dtd_type); 1169*d876124dSJohn Birrell } 1170*d876124dSJohn Birrell } 1171*d876124dSJohn Birrell 1172*d876124dSJohn Birrell src.ctb_file = src_fp; 1173*d876124dSJohn Birrell src.ctb_type = src_type; 1174*d876124dSJohn Birrell src.ctb_dtd = NULL; 1175*d876124dSJohn Birrell 1176*d876124dSJohn Birrell dst.ctb_file = dst_fp; 1177*d876124dSJohn Birrell dst.ctb_type = dst_type; 1178*d876124dSJohn Birrell dst.ctb_dtd = NULL; 1179*d876124dSJohn Birrell 1180*d876124dSJohn Birrell /* 1181*d876124dSJohn Birrell * Now perform kind-specific processing. If dst_type is CTF_ERR, then 1182*d876124dSJohn Birrell * we add a new type with the same properties as src_type to dst_fp. 1183*d876124dSJohn Birrell * If dst_type is not CTF_ERR, then we verify that dst_type has the 1184*d876124dSJohn Birrell * same attributes as src_type. We recurse for embedded references. 1185*d876124dSJohn Birrell */ 1186*d876124dSJohn Birrell switch (kind) { 1187*d876124dSJohn Birrell case CTF_K_INTEGER: 1188*d876124dSJohn Birrell case CTF_K_FLOAT: 1189*d876124dSJohn Birrell if (ctf_type_encoding(src_fp, src_type, &src_en) != 0) 1190*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 1191*d876124dSJohn Birrell 1192*d876124dSJohn Birrell if (dst_type != CTF_ERR) { 1193*d876124dSJohn Birrell if (ctf_type_encoding(dst_fp, dst_type, &dst_en) != 0) 1194*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1195*d876124dSJohn Birrell 1196*d876124dSJohn Birrell if (bcmp(&src_en, &dst_en, sizeof (ctf_encoding_t))) 1197*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1198*d876124dSJohn Birrell 1199*d876124dSJohn Birrell } else if (kind == CTF_K_INTEGER) { 1200*d876124dSJohn Birrell dst_type = ctf_add_integer(dst_fp, flag, name, &src_en); 1201*d876124dSJohn Birrell } else 1202*d876124dSJohn Birrell dst_type = ctf_add_float(dst_fp, flag, name, &src_en); 1203*d876124dSJohn Birrell break; 1204*d876124dSJohn Birrell 1205*d876124dSJohn Birrell case CTF_K_POINTER: 1206*d876124dSJohn Birrell case CTF_K_VOLATILE: 1207*d876124dSJohn Birrell case CTF_K_CONST: 1208*d876124dSJohn Birrell case CTF_K_RESTRICT: 1209*d876124dSJohn Birrell src_type = ctf_type_reference(src_fp, src_type); 1210*d876124dSJohn Birrell src_type = ctf_add_type(dst_fp, src_fp, src_type); 1211*d876124dSJohn Birrell 1212*d876124dSJohn Birrell if (src_type == CTF_ERR) 1213*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1214*d876124dSJohn Birrell 1215*d876124dSJohn Birrell dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind); 1216*d876124dSJohn Birrell break; 1217*d876124dSJohn Birrell 1218*d876124dSJohn Birrell case CTF_K_ARRAY: 1219*d876124dSJohn Birrell if (ctf_array_info(src_fp, src_type, &src_ar) == CTF_ERR) 1220*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); 1221*d876124dSJohn Birrell 1222*d876124dSJohn Birrell src_ar.ctr_contents = 1223*d876124dSJohn Birrell ctf_add_type(dst_fp, src_fp, src_ar.ctr_contents); 1224*d876124dSJohn Birrell src_ar.ctr_index = 1225*d876124dSJohn Birrell ctf_add_type(dst_fp, src_fp, src_ar.ctr_index); 1226*d876124dSJohn Birrell src_ar.ctr_nelems = src_ar.ctr_nelems; 1227*d876124dSJohn Birrell 1228*d876124dSJohn Birrell if (src_ar.ctr_contents == CTF_ERR || 1229*d876124dSJohn Birrell src_ar.ctr_index == CTF_ERR) 1230*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1231*d876124dSJohn Birrell 1232*d876124dSJohn Birrell if (dst_type != CTF_ERR) { 1233*d876124dSJohn Birrell if (ctf_array_info(dst_fp, dst_type, &dst_ar) != 0) 1234*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1235*d876124dSJohn Birrell 1236*d876124dSJohn Birrell if (bcmp(&src_ar, &dst_ar, sizeof (ctf_arinfo_t))) 1237*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1238*d876124dSJohn Birrell } else 1239*d876124dSJohn Birrell dst_type = ctf_add_array(dst_fp, flag, &src_ar); 1240*d876124dSJohn Birrell break; 1241*d876124dSJohn Birrell 1242*d876124dSJohn Birrell case CTF_K_FUNCTION: 1243*d876124dSJohn Birrell ctc.ctc_return = ctf_add_type(dst_fp, src_fp, tp->ctt_type); 1244*d876124dSJohn Birrell ctc.ctc_argc = 0; 1245*d876124dSJohn Birrell ctc.ctc_flags = 0; 1246*d876124dSJohn Birrell 1247*d876124dSJohn Birrell if (ctc.ctc_return == CTF_ERR) 1248*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1249*d876124dSJohn Birrell 1250*d876124dSJohn Birrell dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL); 1251*d876124dSJohn Birrell break; 1252*d876124dSJohn Birrell 1253*d876124dSJohn Birrell case CTF_K_STRUCT: 1254*d876124dSJohn Birrell case CTF_K_UNION: { 1255*d876124dSJohn Birrell ctf_dmdef_t *dmd; 1256*d876124dSJohn Birrell int errs = 0; 1257*d876124dSJohn Birrell 1258*d876124dSJohn Birrell /* 1259*d876124dSJohn Birrell * Technically to match a struct or union we need to check both 1260*d876124dSJohn Birrell * ways (src members vs. dst, dst members vs. src) but we make 1261*d876124dSJohn Birrell * this more optimal by only checking src vs. dst and comparing 1262*d876124dSJohn Birrell * the total size of the structure (which we must do anyway) 1263*d876124dSJohn Birrell * which covers the possibility of dst members not in src. 1264*d876124dSJohn Birrell * This optimization can be defeated for unions, but is so 1265*d876124dSJohn Birrell * pathological as to render it irrelevant for our purposes. 1266*d876124dSJohn Birrell */ 1267*d876124dSJohn Birrell if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { 1268*d876124dSJohn Birrell if (ctf_type_size(src_fp, src_type) != 1269*d876124dSJohn Birrell ctf_type_size(dst_fp, dst_type)) 1270*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1271*d876124dSJohn Birrell 1272*d876124dSJohn Birrell if (ctf_member_iter(src_fp, src_type, membcmp, &dst)) 1273*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1274*d876124dSJohn Birrell 1275*d876124dSJohn Birrell break; 1276*d876124dSJohn Birrell } 1277*d876124dSJohn Birrell 1278*d876124dSJohn Birrell /* 1279*d876124dSJohn Birrell * Unlike the other cases, copying structs and unions is done 1280*d876124dSJohn Birrell * manually so as to avoid repeated lookups in ctf_add_member 1281*d876124dSJohn Birrell * and to ensure the exact same member offsets as in src_type. 1282*d876124dSJohn Birrell */ 1283*d876124dSJohn Birrell dst_type = ctf_add_generic(dst_fp, flag, name, &dtd); 1284*d876124dSJohn Birrell if (dst_type == CTF_ERR) 1285*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1286*d876124dSJohn Birrell 1287*d876124dSJohn Birrell dst.ctb_type = dst_type; 1288*d876124dSJohn Birrell dst.ctb_dtd = dtd; 1289*d876124dSJohn Birrell 1290*d876124dSJohn Birrell if (ctf_member_iter(src_fp, src_type, membadd, &dst) != 0) 1291*d876124dSJohn Birrell errs++; /* increment errs and fail at bottom of case */ 1292*d876124dSJohn Birrell 1293*d876124dSJohn Birrell if ((size = ctf_type_size(src_fp, src_type)) > CTF_MAX_SIZE) { 1294*d876124dSJohn Birrell dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; 1295*d876124dSJohn Birrell dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size); 1296*d876124dSJohn Birrell dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size); 1297*d876124dSJohn Birrell } else 1298*d876124dSJohn Birrell dtd->dtd_data.ctt_size = (ushort_t)size; 1299*d876124dSJohn Birrell 1300*d876124dSJohn Birrell dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, vlen); 1301*d876124dSJohn Birrell 1302*d876124dSJohn Birrell /* 1303*d876124dSJohn Birrell * Make a final pass through the members changing each dmd_type 1304*d876124dSJohn Birrell * (a src_fp type) to an equivalent type in dst_fp. We pass 1305*d876124dSJohn Birrell * through all members, leaving any that fail set to CTF_ERR. 1306*d876124dSJohn Birrell */ 1307*d876124dSJohn Birrell for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); 1308*d876124dSJohn Birrell dmd != NULL; dmd = ctf_list_next(dmd)) { 1309*d876124dSJohn Birrell if ((dmd->dmd_type = ctf_add_type(dst_fp, src_fp, 1310*d876124dSJohn Birrell dmd->dmd_type)) == CTF_ERR) 1311*d876124dSJohn Birrell errs++; 1312*d876124dSJohn Birrell } 1313*d876124dSJohn Birrell 1314*d876124dSJohn Birrell if (errs) 1315*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1316*d876124dSJohn Birrell break; 1317*d876124dSJohn Birrell } 1318*d876124dSJohn Birrell 1319*d876124dSJohn Birrell case CTF_K_ENUM: 1320*d876124dSJohn Birrell if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { 1321*d876124dSJohn Birrell if (ctf_enum_iter(src_fp, src_type, enumcmp, &dst) || 1322*d876124dSJohn Birrell ctf_enum_iter(dst_fp, dst_type, enumcmp, &src)) 1323*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); 1324*d876124dSJohn Birrell } else { 1325*d876124dSJohn Birrell dst_type = ctf_add_enum(dst_fp, flag, name); 1326*d876124dSJohn Birrell if ((dst.ctb_type = dst_type) == CTF_ERR || 1327*d876124dSJohn Birrell ctf_enum_iter(src_fp, src_type, enumadd, &dst)) 1328*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1329*d876124dSJohn Birrell } 1330*d876124dSJohn Birrell break; 1331*d876124dSJohn Birrell 1332*d876124dSJohn Birrell case CTF_K_FORWARD: 1333*d876124dSJohn Birrell if (dst_type == CTF_ERR) { 1334*d876124dSJohn Birrell dst_type = ctf_add_forward(dst_fp, 1335*d876124dSJohn Birrell flag, name, CTF_K_STRUCT); /* assume STRUCT */ 1336*d876124dSJohn Birrell } 1337*d876124dSJohn Birrell break; 1338*d876124dSJohn Birrell 1339*d876124dSJohn Birrell case CTF_K_TYPEDEF: 1340*d876124dSJohn Birrell src_type = ctf_type_reference(src_fp, src_type); 1341*d876124dSJohn Birrell src_type = ctf_add_type(dst_fp, src_fp, src_type); 1342*d876124dSJohn Birrell 1343*d876124dSJohn Birrell if (src_type == CTF_ERR) 1344*d876124dSJohn Birrell return (CTF_ERR); /* errno is set for us */ 1345*d876124dSJohn Birrell 1346*d876124dSJohn Birrell /* 1347*d876124dSJohn Birrell * If dst_type is not CTF_ERR at this point, we should check if 1348*d876124dSJohn Birrell * ctf_type_reference(dst_fp, dst_type) != src_type and if so 1349*d876124dSJohn Birrell * fail with ECTF_CONFLICT. However, this causes problems with 1350*d876124dSJohn Birrell * <sys/types.h> typedefs that vary based on things like if 1351*d876124dSJohn Birrell * _ILP32x then pid_t is int otherwise long. We therefore omit 1352*d876124dSJohn Birrell * this check and assume that if the identically named typedef 1353*d876124dSJohn Birrell * already exists in dst_fp, it is correct or equivalent. 1354*d876124dSJohn Birrell */ 1355*d876124dSJohn Birrell if (dst_type == CTF_ERR) { 1356*d876124dSJohn Birrell dst_type = ctf_add_typedef(dst_fp, flag, 1357*d876124dSJohn Birrell name, src_type); 1358*d876124dSJohn Birrell } 1359*d876124dSJohn Birrell break; 1360*d876124dSJohn Birrell 1361*d876124dSJohn Birrell default: 1362*d876124dSJohn Birrell return (ctf_set_errno(dst_fp, ECTF_CORRUPT)); 1363*d876124dSJohn Birrell } 1364*d876124dSJohn Birrell 1365*d876124dSJohn Birrell return (dst_type); 1366*d876124dSJohn Birrell } 1367