diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_create.c b/cddl/contrib/opensolaris/common/ctf/ctf_create.c index 35a43cc4e790..154cefb775ba 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_create.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_create.c @@ -1,1625 +1,1722 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #include #include #include #include /* * This static string is used as the template for initially populating a * dynamic container's string table. We always store \0 in the first byte, * and we use the generic string "PARENT" to mark this container's parent * if one is associated with the container using ctf_import(). */ static const char _CTF_STRTAB_TEMPLATE[] = "\0PARENT"; /* * To create an empty CTF container, we just declare a zeroed header and call * ctf_bufopen() on it. If ctf_bufopen succeeds, we mark the new container r/w * and initialize the dynamic members. We set dtstrlen to 1 to reserve the * first byte of the string table for a \0 byte, and we start assigning type * IDs at 1 because type ID 0 is used as a sentinel. */ ctf_file_t * ctf_create(int *errp) { static const ctf_header_t hdr = { { CTF_MAGIC, CTF_VERSION, 0 } }; const ulong_t hashlen = 128; ctf_dtdef_t **hash = ctf_alloc(hashlen * sizeof (ctf_dtdef_t *)); ctf_sect_t cts; ctf_file_t *fp; if (hash == NULL) return (ctf_set_open_errno(errp, EAGAIN)); cts.cts_name = _CTF_SECTION; cts.cts_type = SHT_PROGBITS; cts.cts_flags = 0; cts.cts_data = (void *)&hdr; cts.cts_size = sizeof (hdr); cts.cts_entsize = 1; cts.cts_offset = 0; if ((fp = ctf_bufopen(&cts, NULL, NULL, errp)) == NULL) { ctf_free(hash, hashlen * sizeof (ctf_dtdef_t *)); return (NULL); } fp->ctf_flags |= LCTF_RDWR; fp->ctf_dthashlen = hashlen; bzero(hash, hashlen * sizeof (ctf_dtdef_t *)); fp->ctf_dthash = hash; fp->ctf_dtstrlen = sizeof (_CTF_STRTAB_TEMPLATE); fp->ctf_dtnextid = 1; fp->ctf_dtoldid = 0; return (fp); } static uchar_t * -ctf_copy_smembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) +ctf_copy_smembers(const ctf_file_t *fp, ctf_dtdef_t *dtd, uint_t soff, + uchar_t *t) { ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); - ctf_member_t ctm; + size_t sz; + uint_t name; for (; dmd != NULL; dmd = ctf_list_next(dmd)) { if (dmd->dmd_name) { - ctm.ctm_name = soff; + name = soff; soff += strlen(dmd->dmd_name) + 1; } else - ctm.ctm_name = 0; + name = 0; - ctm.ctm_type = (ushort_t)dmd->dmd_type; - ctm.ctm_offset = (ushort_t)dmd->dmd_offset; + if (fp->ctf_version == CTF_VERSION_2) { + struct ctf_member_v2 ctm; - bcopy(&ctm, t, sizeof (ctm)); - t += sizeof (ctm); + ctm.ctm_name = name; + ctm.ctm_type = (ushort_t)dmd->dmd_type; + ctm.ctm_offset = (ushort_t)dmd->dmd_offset; + + sz = sizeof (ctm); + bcopy(&ctm, t, sz); + t += sz; + } else { + struct ctf_member_v3 ctm; + + ctm.ctm_name = name; + ctm.ctm_type = dmd->dmd_type; + ctm.ctm_offset = dmd->dmd_offset; + + sz = sizeof (ctm); + bcopy(&ctm, t, sz); + t += sz; + } } return (t); } static uchar_t * -ctf_copy_lmembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) +ctf_copy_lmembers(const ctf_file_t *fp, ctf_dtdef_t *dtd, uint_t soff, + uchar_t *t) { ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); - ctf_lmember_t ctlm; + size_t sz; + uint_t name; for (; dmd != NULL; dmd = ctf_list_next(dmd)) { if (dmd->dmd_name) { - ctlm.ctlm_name = soff; + name = soff; soff += strlen(dmd->dmd_name) + 1; } else - ctlm.ctlm_name = 0; + name = 0; + + if (fp->ctf_version == CTF_VERSION_2) { + struct ctf_lmember_v2 ctlm; - ctlm.ctlm_type = (ushort_t)dmd->dmd_type; - ctlm.ctlm_pad = 0; - ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); - ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); + ctlm.ctlm_name = name; + ctlm.ctlm_type = (ushort_t)dmd->dmd_type; + ctlm.ctlm_pad = 0; + ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); + ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); - bcopy(&ctlm, t, sizeof (ctlm)); - t += sizeof (ctlm); + sz = sizeof (ctlm); + bcopy(&ctlm, t, sz); + t += sz; + } else { + struct ctf_lmember_v3 ctlm; + + ctlm.ctlm_name = name; + ctlm.ctlm_type = dmd->dmd_type; + ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI(dmd->dmd_offset); + ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO(dmd->dmd_offset); + + sz = sizeof (ctlm); + bcopy(&ctlm, t, sz); + t += sz; + } } return (t); } static uchar_t * ctf_copy_emembers(ctf_dtdef_t *dtd, uint_t soff, uchar_t *t) { ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); ctf_enum_t cte; for (; dmd != NULL; dmd = ctf_list_next(dmd)) { cte.cte_name = soff; cte.cte_value = dmd->dmd_value; soff += strlen(dmd->dmd_name) + 1; bcopy(&cte, t, sizeof (cte)); t += sizeof (cte); } return (t); } static uchar_t * ctf_copy_membnames(ctf_dtdef_t *dtd, uchar_t *s) { ctf_dmdef_t *dmd = ctf_list_next(&dtd->dtd_u.dtu_members); size_t len; for (; dmd != NULL; dmd = ctf_list_next(dmd)) { if (dmd->dmd_name == NULL) continue; /* skip anonymous members */ len = strlen(dmd->dmd_name) + 1; bcopy(dmd->dmd_name, s, len); s += len; } return (s); } /* * Only types of dyanmic CTF containers contain reference counts. These * containers are marked RD/WR. Because of that we basically make this a no-op * for compatability with non-dynamic CTF sections. This is also a no-op for * types which are not dynamic types. It is the responsibility of the caller to * make sure it is a valid type. We help that caller out on debug builds. * * Note that the reference counts are not maintained for types that are not * within this container. In other words if we have a type in a parent, that * will not have its reference count increased. On the flip side, the parent * will not be allowed to remove dynamic types if it has children. */ static void ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); if (dtd == NULL) return; if (!(fp->ctf_flags & LCTF_RDWR)) return; dtd->dtd_ref++; } /* * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the * caller should ensure that this is already a valid type. */ static void ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); if (dtd == NULL) return; if (!(fp->ctf_flags & LCTF_RDWR)) return; ASSERT(dtd->dtd_ref >= 1); dtd->dtd_ref--; } /* * If the specified CTF container is writable and has been modified, reload * this container with the updated type definitions. In order to make this * code and the rest of libctf as simple as possible, we perform updates by * taking the dynamic type definitions and creating an in-memory CTF file * containing the definitions, and then call ctf_bufopen() on it. This not * only leverages ctf_bufopen(), but also avoids having to bifurcate the rest * of the library code with different lookup paths for static and dynamic * type definitions. We are therefore optimizing greatly for lookup over * update, which we assume will be an uncommon operation. We perform one * extra trick here for the benefit of callers and to keep our code simple: * ctf_bufopen() will return a new ctf_file_t, but we want to keep the fp * constant for the caller, so after ctf_bufopen() returns, we use bcopy to * swap the interior of the old and new ctf_file_t's, and then free the old. * * Note that the lists of dynamic types stays around and the resulting container * is still writeable. Furthermore, the reference counts that are on the dtd's * are still valid. */ int ctf_update(ctf_file_t *fp) { ctf_file_t ofp, *nfp; ctf_header_t hdr; ctf_dtdef_t *dtd; ctf_sect_t cts; uchar_t *s, *s0, *t; size_t size; void *buf; int err; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (!(fp->ctf_flags & LCTF_DIRTY)) return (0); /* no update required */ /* * Fill in an initial CTF header. We will leave the label, object, * and function sections empty and only output a header, type section, * and string table. The type section begins at a 4-byte aligned * boundary past the CTF header itself (at relative offset zero). */ bzero(&hdr, sizeof (hdr)); hdr.cth_magic = CTF_MAGIC; - hdr.cth_version = CTF_VERSION; + hdr.cth_version = fp->ctf_version; if (fp->ctf_flags & LCTF_CHILD) hdr.cth_parname = 1; /* i.e. _CTF_STRTAB_TEMPLATE[1] */ /* * Iterate through the dynamic type definition list and compute the * size of the CTF type section we will need to generate. */ for (size = 0, dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ctf_list_next(dtd)) { - uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); - uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); + uint_t kind = LCTF_INFO_KIND(fp, dtd->dtd_data.ctt_info); + uint_t vlen = LCTF_INFO_VLEN(fp, dtd->dtd_data.ctt_info); - if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) - size += sizeof (ctf_stype_t); - else - size += sizeof (ctf_type_t); + if (fp->ctf_version == CTF_VERSION_2) { + if (dtd->dtd_data.ctt_size != CTF_V2_LSIZE_SENT) + size += sizeof (struct ctf_stype_v2); + else + size += sizeof (struct ctf_type_v2); + } else { + if (dtd->dtd_data.ctt_size != LCTF_LSIZE_SENT(fp)) + size += sizeof (struct ctf_stype_v3); + else + size += sizeof (struct ctf_type_v3); + } switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: size += sizeof (uint_t); break; case CTF_K_ARRAY: - size += sizeof (ctf_array_t); + size += fp->ctf_version == CTF_VERSION_2 ? + sizeof (struct ctf_array_v2) : + sizeof (struct ctf_array_v3); break; case CTF_K_FUNCTION: - size += sizeof (ushort_t) * (vlen + (vlen & 1)); + size += roundup2(fp->ctf_idwidth * vlen, 4); break; case CTF_K_STRUCT: case CTF_K_UNION: - if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) - size += sizeof (ctf_member_t) * vlen; - else - size += sizeof (ctf_lmember_t) * vlen; + if (fp->ctf_version == CTF_VERSION_2) { + if (dtd->dtd_data.ctt_size < + LCTF_LSTRUCT_THRESH(fp)) + size += sizeof (struct ctf_member_v2) * + vlen; + else + size += sizeof (struct ctf_lmember_v2) * + vlen; + } else { + if (dtd->dtd_data.ctt_size < + LCTF_LSTRUCT_THRESH(fp)) + size += sizeof (struct ctf_member_v3) * + vlen; + else + size += sizeof (struct ctf_lmember_v3) * + vlen; + } break; case CTF_K_ENUM: size += sizeof (ctf_enum_t) * vlen; break; } } /* * Fill in the string table offset and size, compute the size of the * entire CTF buffer we need, and then allocate a new buffer and * bcopy the finished header to the start of the buffer. */ hdr.cth_stroff = hdr.cth_typeoff + size; hdr.cth_strlen = fp->ctf_dtstrlen; size = sizeof (ctf_header_t) + hdr.cth_stroff + hdr.cth_strlen; if ((buf = ctf_data_alloc(size)) == MAP_FAILED) return (ctf_set_errno(fp, EAGAIN)); bcopy(&hdr, buf, sizeof (ctf_header_t)); t = (uchar_t *)buf + sizeof (ctf_header_t); s = s0 = (uchar_t *)buf + sizeof (ctf_header_t) + hdr.cth_stroff; bcopy(_CTF_STRTAB_TEMPLATE, s, sizeof (_CTF_STRTAB_TEMPLATE)); s += sizeof (_CTF_STRTAB_TEMPLATE); /* * We now take a final lap through the dynamic type definition list and * copy the appropriate type records and strings to the output buffer. */ for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ctf_list_next(dtd)) { + void *tp; + uint_t kind = LCTF_INFO_KIND(fp, dtd->dtd_data.ctt_info); + uint_t vlen = LCTF_INFO_VLEN(fp, dtd->dtd_data.ctt_info); + struct ctf_type_v2 ctt; - uint_t kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); - uint_t vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); - - ctf_array_t cta; uint_t encoding; size_t len; if (dtd->dtd_name != NULL) { dtd->dtd_data.ctt_name = (uint_t)(s - s0); len = strlen(dtd->dtd_name) + 1; bcopy(dtd->dtd_name, s, len); s += len; } else dtd->dtd_data.ctt_name = 0; - if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) - len = sizeof (ctf_stype_t); - else - len = sizeof (ctf_type_t); + if (fp->ctf_version == CTF_VERSION_2) { + ctt.ctt_name = dtd->dtd_data.ctt_name; + ctt.ctt_info = (ushort_t)dtd->dtd_data.ctt_info; + ctt.ctt_size = (ushort_t)dtd->dtd_data.ctt_size; + if (dtd->dtd_data.ctt_size != CTF_V2_LSIZE_SENT) + len = sizeof (struct ctf_stype_v2); + else { + len = sizeof (struct ctf_type_v2); + ctt.ctt_lsizehi = dtd->dtd_data.ctt_lsizehi; + ctt.ctt_lsizelo = dtd->dtd_data.ctt_lsizelo; + } + tp = &ctt; + } else { + if (dtd->dtd_data.ctt_size != LCTF_LSIZE_SENT(fp)) + len = sizeof (struct ctf_stype_v3); + else + len = sizeof (struct ctf_type_v3); + tp = &dtd->dtd_data; + } - bcopy(&dtd->dtd_data, t, len); + bcopy(tp, t, len); t += len; switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: if (kind == CTF_K_INTEGER) { encoding = CTF_INT_DATA( dtd->dtd_u.dtu_enc.cte_format, dtd->dtd_u.dtu_enc.cte_offset, dtd->dtd_u.dtu_enc.cte_bits); } else { encoding = CTF_FP_DATA( dtd->dtd_u.dtu_enc.cte_format, dtd->dtd_u.dtu_enc.cte_offset, dtd->dtd_u.dtu_enc.cte_bits); } bcopy(&encoding, t, sizeof (encoding)); t += sizeof (encoding); break; case CTF_K_ARRAY: - cta.cta_contents = (ushort_t) - dtd->dtd_u.dtu_arr.ctr_contents; - cta.cta_index = (ushort_t) - dtd->dtd_u.dtu_arr.ctr_index; - cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; - bcopy(&cta, t, sizeof (cta)); - t += sizeof (cta); + if (fp->ctf_version == CTF_VERSION_2) { + struct ctf_array_v2 cta; + + cta.cta_contents = + (uint16_t)dtd->dtd_u.dtu_arr.ctr_contents; + cta.cta_index = + (uint16_t)dtd->dtd_u.dtu_arr.ctr_index; + cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; + + bcopy(&cta, t, sizeof (cta)); + t += sizeof (cta); + } else { + struct ctf_array_v3 cta; + + cta.cta_contents = + dtd->dtd_u.dtu_arr.ctr_contents; + cta.cta_index = dtd->dtd_u.dtu_arr.ctr_index; + cta.cta_nelems = dtd->dtd_u.dtu_arr.ctr_nelems; + + bcopy(&cta, t, sizeof (cta)); + t += sizeof (cta); + } break; case CTF_K_FUNCTION: { - ushort_t *argv = (ushort_t *)(uintptr_t)t; + char *argv = (char *)(uintptr_t)t; uint_t argc; - for (argc = 0; argc < vlen; argc++) - *argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc]; + if (fp->ctf_version == CTF_VERSION_2) { + ushort_t arg; - if (vlen & 1) - *argv++ = 0; /* pad to 4-byte boundary */ + for (argc = 0; argc < vlen; + argc++, argv += sizeof(arg)) { + arg = + (ushort_t)dtd->dtd_u.dtu_argv[argc]; + memcpy(argv, &arg, sizeof(arg)); + } + } else { + uint_t arg; + + for (argc = 0; argc < vlen; + argc++, argv += sizeof(arg)) { + arg = (uint_t)dtd->dtd_u.dtu_argv[argc]; + memcpy(argv, &arg, sizeof(arg)); + } + } t = (uchar_t *)argv; break; } case CTF_K_STRUCT: case CTF_K_UNION: - if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) - t = ctf_copy_smembers(dtd, (uint_t)(s - s0), t); + if (dtd->dtd_data.ctt_size < LCTF_LSTRUCT_THRESH(fp)) + t = ctf_copy_smembers(fp, dtd, (uint_t)(s - s0), + t); else - t = ctf_copy_lmembers(dtd, (uint_t)(s - s0), t); + t = ctf_copy_lmembers(fp, dtd, (uint_t)(s - s0), + t); s = ctf_copy_membnames(dtd, s); break; case CTF_K_ENUM: t = ctf_copy_emembers(dtd, (uint_t)(s - s0), t); s = ctf_copy_membnames(dtd, s); break; } } /* * Finally, we are ready to ctf_bufopen() the new container. If this * is successful, we then switch nfp and fp and free the old container. */ ctf_data_protect(buf, size); cts.cts_name = _CTF_SECTION; cts.cts_type = SHT_PROGBITS; cts.cts_flags = 0; cts.cts_data = buf; cts.cts_size = size; cts.cts_entsize = 1; cts.cts_offset = 0; if ((nfp = ctf_bufopen(&cts, NULL, NULL, &err)) == NULL) { ctf_data_free(buf, size); return (ctf_set_errno(fp, err)); } (void) ctf_setmodel(nfp, ctf_getmodel(fp)); (void) ctf_import(nfp, fp->ctf_parent); nfp->ctf_refcnt = fp->ctf_refcnt; nfp->ctf_flags |= fp->ctf_flags & ~LCTF_DIRTY; nfp->ctf_data.cts_data = NULL; /* force ctf_data_free() on close */ nfp->ctf_dthash = fp->ctf_dthash; nfp->ctf_dthashlen = fp->ctf_dthashlen; nfp->ctf_dtdefs = fp->ctf_dtdefs; nfp->ctf_dtstrlen = fp->ctf_dtstrlen; nfp->ctf_dtnextid = fp->ctf_dtnextid; nfp->ctf_dtoldid = fp->ctf_dtnextid - 1; nfp->ctf_specific = fp->ctf_specific; fp->ctf_dthash = NULL; fp->ctf_dthashlen = 0; bzero(&fp->ctf_dtdefs, sizeof (ctf_list_t)); bcopy(fp, &ofp, sizeof (ctf_file_t)); bcopy(nfp, fp, sizeof (ctf_file_t)); bcopy(&ofp, nfp, sizeof (ctf_file_t)); /* * Initialize the ctf_lookup_by_name top-level dictionary. We keep an * array of type name prefixes and the corresponding ctf_hash to use. * NOTE: This code must be kept in sync with the code in ctf_bufopen(). */ fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; nfp->ctf_refcnt = 1; /* force nfp to be freed */ ctf_close(nfp); return (0); } void ctf_dtd_insert(ctf_file_t *fp, ctf_dtdef_t *dtd) { ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); dtd->dtd_hash = fp->ctf_dthash[h]; fp->ctf_dthash[h] = dtd; ctf_list_append(&fp->ctf_dtdefs, dtd); } void ctf_dtd_delete(ctf_file_t *fp, ctf_dtdef_t *dtd) { ulong_t h = dtd->dtd_type & (fp->ctf_dthashlen - 1); ctf_dtdef_t *p, **q = &fp->ctf_dthash[h]; ctf_dmdef_t *dmd, *nmd; size_t len; int kind, i; for (p = *q; p != NULL; p = p->dtd_hash) { if (p != dtd) q = &p->dtd_hash; else break; } if (p != NULL) *q = p->dtd_hash; - kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); + kind = LCTF_INFO_KIND(fp, dtd->dtd_data.ctt_info); switch (kind) { case CTF_K_STRUCT: case CTF_K_UNION: case CTF_K_ENUM: for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = nmd) { if (dmd->dmd_name != NULL) { len = strlen(dmd->dmd_name) + 1; ctf_free(dmd->dmd_name, len); fp->ctf_dtstrlen -= len; } if (kind != CTF_K_ENUM) ctf_ref_dec(fp, dmd->dmd_type); nmd = ctf_list_next(dmd); ctf_free(dmd, sizeof (ctf_dmdef_t)); } break; case CTF_K_FUNCTION: ctf_ref_dec(fp, dtd->dtd_data.ctt_type); - for (i = 0; i < CTF_INFO_VLEN(dtd->dtd_data.ctt_info); i++) + for (i = 0; i < LCTF_INFO_VLEN(fp, dtd->dtd_data.ctt_info); i++) if (dtd->dtd_u.dtu_argv[i] != 0) ctf_ref_dec(fp, dtd->dtd_u.dtu_argv[i]); ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) * - CTF_INFO_VLEN(dtd->dtd_data.ctt_info)); + LCTF_INFO_VLEN(fp, dtd->dtd_data.ctt_info)); break; case CTF_K_ARRAY: ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); break; case CTF_K_TYPEDEF: ctf_ref_dec(fp, dtd->dtd_data.ctt_type); break; case CTF_K_POINTER: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: ctf_ref_dec(fp, dtd->dtd_data.ctt_type); break; } if (dtd->dtd_name) { len = strlen(dtd->dtd_name) + 1; ctf_free(dtd->dtd_name, len); fp->ctf_dtstrlen -= len; } ctf_list_delete(&fp->ctf_dtdefs, dtd); ctf_free(dtd, sizeof (ctf_dtdef_t)); } ctf_dtdef_t * ctf_dtd_lookup(ctf_file_t *fp, ctf_id_t type) { ulong_t h = type & (fp->ctf_dthashlen - 1); ctf_dtdef_t *dtd; if (fp->ctf_dthash == NULL) return (NULL); for (dtd = fp->ctf_dthash[h]; dtd != NULL; dtd = dtd->dtd_hash) { if (dtd->dtd_type == type) break; } return (dtd); } /* * Discard all of the dynamic type definitions that have been added to the * container since the last call to ctf_update(). We locate such types by * scanning the list and deleting elements that have type IDs greater than * ctf_dtoldid, which is set by ctf_update(), above. Note that to work properly * with our reference counting schemes, we must delete the dynamic list in * reverse. */ int ctf_discard(ctf_file_t *fp) { ctf_dtdef_t *dtd, *ntd; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (!(fp->ctf_flags & LCTF_DIRTY)) return (0); /* no update required */ for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { ntd = ctf_list_prev(dtd); - if (CTF_TYPE_TO_INDEX(dtd->dtd_type) <= fp->ctf_dtoldid) + if (LCTF_TYPE_TO_INDEX(fp, dtd->dtd_type) <= fp->ctf_dtoldid) continue; /* skip types that have been committed */ ctf_dtd_delete(fp, dtd); } fp->ctf_dtnextid = fp->ctf_dtoldid + 1; fp->ctf_flags &= ~LCTF_DIRTY; return (0); } static ctf_id_t ctf_add_generic(ctf_file_t *fp, uint_t flag, const char *name, ctf_dtdef_t **rp) { ctf_dtdef_t *dtd; ctf_id_t type; char *s = NULL; if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT) return (ctf_set_errno(fp, EINVAL)); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); - if (CTF_INDEX_TO_TYPE(fp->ctf_dtnextid, 1) > CTF_MAX_TYPE) + if (LCTF_INDEX_TO_TYPE(fp, fp->ctf_dtnextid, 1) > LCTF_MAX_TYPE(fp)) return (ctf_set_errno(fp, ECTF_FULL)); if ((dtd = ctf_alloc(sizeof (ctf_dtdef_t))) == NULL) return (ctf_set_errno(fp, EAGAIN)); if (name != NULL && *name != '\0' && (s = ctf_strdup(name)) == NULL) { ctf_free(dtd, sizeof (ctf_dtdef_t)); return (ctf_set_errno(fp, EAGAIN)); } type = fp->ctf_dtnextid++; - type = CTF_INDEX_TO_TYPE(type, (fp->ctf_flags & LCTF_CHILD)); + type = LCTF_INDEX_TO_TYPE(fp, type, (fp->ctf_flags & LCTF_CHILD)); bzero(dtd, sizeof (ctf_dtdef_t)); dtd->dtd_name = s; dtd->dtd_type = type; if (s != NULL) fp->ctf_dtstrlen += strlen(s) + 1; ctf_dtd_insert(fp, dtd); fp->ctf_flags |= LCTF_DIRTY; *rp = dtd; return (type); } /* * When encoding integer sizes, we want to convert a byte count in the range * 1-8 to the closest power of 2 (e.g. 3->4, 5->8, etc). The clp2() function * is a clever implementation from "Hacker's Delight" by Henry Warren, Jr. */ static size_t clp2(size_t x) { x--; x |= (x >> 1); x |= (x >> 2); x |= (x >> 4); x |= (x >> 8); x |= (x >> 16); return (x + 1); } static ctf_id_t ctf_add_encoded(ctf_file_t *fp, uint_t flag, const char *name, const ctf_encoding_t *ep, uint_t kind) { ctf_dtdef_t *dtd; ctf_id_t type; if (ep == NULL) return (ctf_set_errno(fp, EINVAL)); if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, kind, flag, 0); dtd->dtd_data.ctt_size = clp2(P2ROUNDUP(ep->cte_bits, NBBY) / NBBY); dtd->dtd_u.dtu_enc = *ep; return (type); } static ctf_id_t ctf_add_reftype(ctf_file_t *fp, uint_t flag, ctf_id_t ref, uint_t kind) { ctf_dtdef_t *dtd; ctf_id_t type; - if (ref == CTF_ERR || ref < 0 || ref > CTF_MAX_TYPE) + if (ref == CTF_ERR || ref > LCTF_MAX_TYPE(fp)) return (ctf_set_errno(fp, EINVAL)); if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ ctf_ref_inc(fp, ref); - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, 0); - dtd->dtd_data.ctt_type = (ushort_t)ref; + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, kind, flag, 0); + dtd->dtd_data.ctt_type = (uint_t)ref; return (type); } ctf_id_t ctf_add_integer(ctf_file_t *fp, uint_t flag, const char *name, const ctf_encoding_t *ep) { return (ctf_add_encoded(fp, flag, name, ep, CTF_K_INTEGER)); } ctf_id_t ctf_add_float(ctf_file_t *fp, uint_t flag, const char *name, const ctf_encoding_t *ep) { return (ctf_add_encoded(fp, flag, name, ep, CTF_K_FLOAT)); } ctf_id_t ctf_add_pointer(ctf_file_t *fp, uint_t flag, ctf_id_t ref) { return (ctf_add_reftype(fp, flag, ref, CTF_K_POINTER)); } ctf_id_t ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) { ctf_dtdef_t *dtd; ctf_id_t type; ctf_file_t *fpd; if (arp == NULL) return (ctf_set_errno(fp, EINVAL)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && ctf_dtd_lookup(fp, arp->ctr_index) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_ARRAY, flag, 0); dtd->dtd_data.ctt_size = 0; dtd->dtd_u.dtu_arr = *arp; ctf_ref_inc(fp, arp->ctr_contents); ctf_ref_inc(fp, arp->ctr_index); return (type); } int ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) { ctf_file_t *fpd; ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); - if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) + if (dtd == NULL || + LCTF_INFO_KIND(fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY) return (ctf_set_errno(fp, ECTF_BADID)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && ctf_dtd_lookup(fp, arp->ctr_index) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); fp->ctf_flags |= LCTF_DIRTY; dtd->dtd_u.dtu_arr = *arp; ctf_ref_inc(fp, arp->ctr_contents); ctf_ref_inc(fp, arp->ctr_index); return (0); } ctf_id_t ctf_add_function(ctf_file_t *fp, uint_t flag, const ctf_funcinfo_t *ctc, const ctf_id_t *argv) { ctf_dtdef_t *dtd; ctf_id_t type; uint_t vlen; int i; ctf_id_t *vdat = NULL; ctf_file_t *fpd; if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || (ctc->ctc_argc != 0 && argv == NULL)) return (ctf_set_errno(fp, EINVAL)); vlen = ctc->ctc_argc; if (ctc->ctc_flags & CTF_FUNC_VARARG) vlen++; /* add trailing zero to indicate varargs (see below) */ - if (vlen > CTF_MAX_VLEN) + if (vlen > LCTF_MAX_VLEN(fp)) return (ctf_set_errno(fp, EOVERFLOW)); fpd = fp; if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL && ctf_dtd_lookup(fp, ctc->ctc_return) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); for (i = 0; i < ctc->ctc_argc; i++) { fpd = fp; if (ctf_lookup_by_id(&fpd, argv[i]) == NULL && ctf_dtd_lookup(fp, argv[i]) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); } if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) return (ctf_set_errno(fp, EAGAIN)); if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) { ctf_free(vdat, sizeof (ctf_id_t) * vlen); return (CTF_ERR); /* errno is set for us */ } - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); - dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_FUNCTION, flag, vlen); + dtd->dtd_data.ctt_type = ctc->ctc_return; ctf_ref_inc(fp, ctc->ctc_return); for (i = 0; i < ctc->ctc_argc; i++) ctf_ref_inc(fp, argv[i]); bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); if (ctc->ctc_flags & CTF_FUNC_VARARG) vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ dtd->dtd_u.dtu_argv = vdat; return (type); } ctf_id_t ctf_add_struct(ctf_file_t *fp, uint_t flag, const char *name) { ctf_hash_t *hp = &fp->ctf_structs; ctf_helem_t *hep = NULL; ctf_dtdef_t *dtd; ctf_id_t type; if (name != NULL) hep = ctf_hash_lookup(hp, fp, name, strlen(name)); if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup(fp, type = hep->h_type); else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_STRUCT, flag, 0); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_STRUCT, flag, 0); dtd->dtd_data.ctt_size = 0; return (type); } ctf_id_t ctf_add_union(ctf_file_t *fp, uint_t flag, const char *name) { ctf_hash_t *hp = &fp->ctf_unions; ctf_helem_t *hep = NULL; ctf_dtdef_t *dtd; ctf_id_t type; if (name != NULL) hep = ctf_hash_lookup(hp, fp, name, strlen(name)); if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup(fp, type = hep->h_type); else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_UNION, flag, 0); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_UNION, flag, 0); dtd->dtd_data.ctt_size = 0; return (type); } ctf_id_t ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name) { ctf_hash_t *hp = &fp->ctf_enums; ctf_helem_t *hep = NULL; ctf_dtdef_t *dtd; ctf_id_t type; if (name != NULL) hep = ctf_hash_lookup(hp, fp, name, strlen(name)); if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup(fp, type = hep->h_type); else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_ENUM, flag, 0); dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int; return (type); } ctf_id_t ctf_add_forward(ctf_file_t *fp, uint_t flag, const char *name, uint_t kind) { ctf_hash_t *hp; ctf_helem_t *hep; ctf_dtdef_t *dtd; ctf_id_t type; switch (kind) { case CTF_K_STRUCT: hp = &fp->ctf_structs; break; case CTF_K_UNION: hp = &fp->ctf_unions; break; case CTF_K_ENUM: hp = &fp->ctf_enums; break; default: return (ctf_set_errno(fp, ECTF_NOTSUE)); } /* * If the type is already defined or exists as a forward tag, just * return the ctf_id_t of the existing definition. */ if (name != NULL && (hep = ctf_hash_lookup(hp, fp, name, strlen(name))) != NULL) return (hep->h_type); if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FORWARD, flag, 0); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_FORWARD, flag, 0); dtd->dtd_data.ctt_type = kind; return (type); } ctf_id_t ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) { ctf_dtdef_t *dtd; ctf_id_t type; ctf_file_t *fpd; fpd = fp; if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL && ctf_dtd_lookup(fp, ref) == NULL)) return (ctf_set_errno(fp, EINVAL)); if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); - dtd->dtd_data.ctt_type = (ushort_t)ref; + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, CTF_K_TYPEDEF, flag, 0); + dtd->dtd_data.ctt_type = ref; ctf_ref_inc(fp, ref); return (type); } ctf_id_t ctf_add_volatile(ctf_file_t *fp, uint_t flag, ctf_id_t ref) { return (ctf_add_reftype(fp, flag, ref, CTF_K_VOLATILE)); } ctf_id_t ctf_add_const(ctf_file_t *fp, uint_t flag, ctf_id_t ref) { return (ctf_add_reftype(fp, flag, ref, CTF_K_CONST)); } ctf_id_t ctf_add_restrict(ctf_file_t *fp, uint_t flag, ctf_id_t ref) { return (ctf_add_reftype(fp, flag, ref, CTF_K_RESTRICT)); } int ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid); ctf_dmdef_t *dmd; uint_t kind, vlen, root; char *s; if (name == NULL) return (ctf_set_errno(fp, EINVAL)); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (dtd == NULL) return (ctf_set_errno(fp, ECTF_BADID)); - kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); - root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); - vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); + kind = LCTF_INFO_KIND(fp, dtd->dtd_data.ctt_info); + root = LCTF_INFO_ROOT(fp, dtd->dtd_data.ctt_info); + vlen = LCTF_INFO_VLEN(fp, dtd->dtd_data.ctt_info); if (kind != CTF_K_ENUM) return (ctf_set_errno(fp, ECTF_NOTENUM)); - if (vlen == CTF_MAX_VLEN) + if (vlen > LCTF_MAX_VLEN(fp)) return (ctf_set_errno(fp, ECTF_DTFULL)); for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = ctf_list_next(dmd)) { if (strcmp(dmd->dmd_name, name) == 0) return (ctf_set_errno(fp, ECTF_DUPMEMBER)); } if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) return (ctf_set_errno(fp, EAGAIN)); if ((s = ctf_strdup(name)) == NULL) { ctf_free(dmd, sizeof (ctf_dmdef_t)); return (ctf_set_errno(fp, EAGAIN)); } dmd->dmd_name = s; dmd->dmd_type = CTF_ERR; dmd->dmd_offset = 0; dmd->dmd_value = value; - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, kind, root, vlen + 1); ctf_list_append(&dtd->dtd_u.dtu_members, dmd); fp->ctf_dtstrlen += strlen(s) + 1; fp->ctf_flags |= LCTF_DIRTY; return (0); } int ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid); ctf_dmdef_t *dmd; ssize_t msize, malign, ssize; uint_t kind, vlen, root; char *s = NULL; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (dtd == NULL) return (ctf_set_errno(fp, ECTF_BADID)); - kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); - root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); - vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); + kind = LCTF_INFO_KIND(fp, dtd->dtd_data.ctt_info); + root = LCTF_INFO_ROOT(fp, dtd->dtd_data.ctt_info); + vlen = LCTF_INFO_VLEN(fp, dtd->dtd_data.ctt_info); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno(fp, ECTF_NOTSOU)); - if (vlen == CTF_MAX_VLEN) + if (vlen > LCTF_MAX_VLEN(fp)) return (ctf_set_errno(fp, ECTF_DTFULL)); if (name != NULL) { for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = ctf_list_next(dmd)) { if (dmd->dmd_name != NULL && strcmp(dmd->dmd_name, name) == 0) return (ctf_set_errno(fp, ECTF_DUPMEMBER)); } } if ((msize = ctf_type_size(fp, type)) == CTF_ERR || (malign = ctf_type_align(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) return (ctf_set_errno(fp, EAGAIN)); if (name != NULL && (s = ctf_strdup(name)) == NULL) { ctf_free(dmd, sizeof (ctf_dmdef_t)); return (ctf_set_errno(fp, EAGAIN)); } dmd->dmd_name = s; dmd->dmd_type = type; dmd->dmd_value = -1; if (kind == CTF_K_STRUCT && vlen != 0) { ctf_dmdef_t *lmd = ctf_list_prev(&dtd->dtd_u.dtu_members); ctf_id_t ltype = ctf_type_resolve(fp, lmd->dmd_type); size_t off = lmd->dmd_offset; ctf_encoding_t linfo; ssize_t lsize; if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR) off += linfo.cte_bits; else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR) off += lsize * NBBY; /* * Round up the offset of the end of the last member to the * next byte boundary, convert 'off' to bytes, and then round * it up again to the next multiple of the alignment required * by the new member. Finally, convert back to bits and store * the result in dmd_offset. Technically we could do more * efficient packing if the new member is a bit-field, but * we're the "compiler" and ANSI says we can do as we choose. */ off = roundup(off, NBBY) / NBBY; off = roundup(off, MAX(malign, 1)); dmd->dmd_offset = off * NBBY; ssize = off + msize; } else { dmd->dmd_offset = 0; ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL); ssize = MAX(ssize, msize); } - if (ssize > CTF_MAX_SIZE) { - dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; + if (ssize > LCTF_MAX_SIZE(fp)) { + dtd->dtd_data.ctt_size = LCTF_LSIZE_SENT(fp); dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(ssize); dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(ssize); } else - dtd->dtd_data.ctt_size = (ushort_t)ssize; + dtd->dtd_data.ctt_size = ssize; - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(fp, kind, root, vlen + 1); ctf_list_append(&dtd->dtd_u.dtu_members, dmd); if (s != NULL) fp->ctf_dtstrlen += strlen(s) + 1; ctf_ref_inc(fp, type); fp->ctf_flags |= LCTF_DIRTY; return (0); } /* * This removes a type from the dynamic section. This will fail if the type is * referenced by another type. Note that the CTF ID is never reused currently by * CTF. Note that if this container is a parent container then we just outright * refuse to remove the type. There currently is no notion of searching for the * ctf_dtdef_t in parent containers. If there is, then this constraint could * become finer grained. */ int ctf_delete_type(ctf_file_t *fp, ctf_id_t type) { ctf_file_t *fpd; ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); /* * We want to give as useful an errno as possible. That means that we * want to distinguish between a type which does not exist and one for * which the type is not dynamic. */ fpd = fp; if (ctf_lookup_by_id(&fpd, type) == NULL && ctf_dtd_lookup(fp, type) == NULL) return (CTF_ERR); /* errno is set for us */ if (dtd == NULL) return (ctf_set_errno(fp, ECTF_NOTDYN)); if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1) return (ctf_set_errno(fp, ECTF_REFERENCED)); ctf_dtd_delete(fp, dtd); fp->ctf_flags |= LCTF_DIRTY; return (0); } static int enumcmp(const char *name, int value, void *arg) { ctf_bundle_t *ctb = arg; int bvalue; return (ctf_enum_value(ctb->ctb_file, ctb->ctb_type, name, &bvalue) == CTF_ERR || value != bvalue); } static int enumadd(const char *name, int value, void *arg) { ctf_bundle_t *ctb = arg; return (ctf_add_enumerator(ctb->ctb_file, ctb->ctb_type, name, value) == CTF_ERR); } static int membadd(const char *name, ctf_id_t type, ulong_t offset, void *arg) { ctf_bundle_t *ctb = arg; ctf_dmdef_t *dmd; char *s = NULL; if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) return (ctf_set_errno(ctb->ctb_file, EAGAIN)); if (name != NULL && *name != '\0' && (s = ctf_strdup(name)) == NULL) { ctf_free(dmd, sizeof (ctf_dmdef_t)); return (ctf_set_errno(ctb->ctb_file, EAGAIN)); } /* * For now, dmd_type is copied as the src_fp's type; it is reset to an * equivalent dst_fp type by a final loop in ctf_add_type(), below. */ dmd->dmd_name = s; dmd->dmd_type = type; dmd->dmd_offset = offset; dmd->dmd_value = -1; ctf_list_append(&ctb->ctb_dtd->dtd_u.dtu_members, dmd); if (s != NULL) ctb->ctb_file->ctf_dtstrlen += strlen(s) + 1; ctb->ctb_file->ctf_flags |= LCTF_DIRTY; return (0); } static long soucmp(ctf_file_t *src_fp, ctf_id_t src_type, ctf_file_t *dst_fp, ctf_id_t dst_type) { - const ctf_type_t *src_tp, *dst_tp; + const void *src_tp, *dst_tp; const char *src_name, *dst_name; ssize_t src_sz, dst_sz, src_inc, dst_inc; - uint_t kind, n; + uint_t dst_kind, dst_vlen, src_kind, src_vlen, n; if ((src_type = ctf_type_resolve(src_fp, src_type)) == CTF_ERR) return (CTF_ERR); if ((dst_type = ctf_type_resolve(dst_fp, dst_type)) == CTF_ERR) return (CTF_ERR); if ((src_tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL) return (CTF_ERR); if ((dst_tp = ctf_lookup_by_id(&dst_fp, dst_type)) == NULL) return (CTF_ERR); - if ((kind = LCTF_INFO_KIND(src_fp, src_tp->ctt_info)) != - LCTF_INFO_KIND(dst_fp, dst_tp->ctt_info)) + ctf_get_ctt_info(src_fp, src_tp, &src_kind, &src_vlen, NULL); + ctf_get_ctt_info(dst_fp, dst_tp, &dst_kind, &dst_vlen, NULL); + + if (src_kind != dst_kind) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) + if (src_kind != CTF_K_STRUCT && src_kind != CTF_K_UNION) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - if ((n = LCTF_INFO_VLEN(src_fp, src_tp->ctt_info)) != - LCTF_INFO_VLEN(dst_fp, dst_tp->ctt_info)) + if (src_vlen != dst_vlen) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); (void) ctf_get_ctt_size(src_fp, src_tp, &src_sz, &src_inc); (void) ctf_get_ctt_size(dst_fp, dst_tp, &dst_sz, &dst_inc); - if (src_sz != dst_sz || src_inc != dst_inc) + if (src_sz != dst_sz) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - if (src_sz < CTF_LSTRUCT_THRESH) { - const ctf_member_t *src_mp, *dst_mp; + const char *src_mp, *dst_mp; + ulong_t src_offset, dst_offset; - src_mp = (const ctf_member_t *)((uintptr_t)src_tp + src_inc); - dst_mp = (const ctf_member_t *)((uintptr_t)dst_tp + dst_inc); - for (; n != 0; n--, src_mp++, dst_mp++) { - if (src_mp->ctm_offset != dst_mp->ctm_offset) - return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - src_name = ctf_strptr(src_fp, src_mp->ctm_name); - dst_name = ctf_strptr(dst_fp, dst_mp->ctm_name); - if (strcmp(src_name, dst_name) != 0) - return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - } - } else { - const ctf_lmember_t *src_mp, *dst_mp; + src_mp = (const char *)src_tp + src_inc; + dst_mp = (const char *)dst_tp + dst_inc; + for (n = src_vlen; n != 0; + n--, src_mp += src_inc, dst_mp += dst_inc) { + ctf_get_ctm_info(src_fp, src_mp, src_sz, &src_inc, NULL, + &src_offset, &src_name); + ctf_get_ctm_info(dst_fp, dst_mp, dst_sz, &dst_inc, NULL, + &dst_offset, &dst_name); - src_mp = (const ctf_lmember_t *)((uintptr_t)src_tp + src_inc); - dst_mp = (const ctf_lmember_t *)((uintptr_t)dst_tp + dst_inc); - for (; n != 0; n--, src_mp++, dst_mp++) { - if (src_mp->ctlm_offsethi != dst_mp->ctlm_offsethi || - src_mp->ctlm_offsetlo != dst_mp->ctlm_offsetlo) - return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - src_name = ctf_strptr(src_fp, src_mp->ctlm_name); - dst_name = ctf_strptr(dst_fp, dst_mp->ctlm_name); - if (strcmp(src_name, dst_name) != 0) - return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); - } + if (src_offset != dst_offset) + return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); + if (strcmp(src_name, dst_name) != 0) + return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); } return (0); } /* * The ctf_add_type routine is used to copy a type from a source CTF container * to a dynamic destination container. This routine operates recursively by * following the source type's links and embedded member types. If the * destination container already contains a named type which has the same * attributes, then we succeed and return this type but no changes occur. */ ctf_id_t ctf_add_type(ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) { ctf_id_t dst_type = CTF_ERR; uint_t dst_kind = CTF_K_UNKNOWN; - const ctf_type_t *tp; + const void *tp; const char *name; - uint_t kind, flag, vlen; + uint_t type, kind, flag, vlen; ctf_bundle_t src, dst; ctf_encoding_t src_en, main_en, dst_en; ctf_arinfo_t src_ar, dst_ar; ctf_dtdef_t *dtd; ctf_funcinfo_t ctc; ssize_t size; ctf_hash_t *hp; ctf_helem_t *hep; if (dst_fp == src_fp) return (src_type); if (!(dst_fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(dst_fp, ECTF_RDONLY)); if ((tp = ctf_lookup_by_id(&src_fp, src_type)) == NULL) return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); - name = ctf_strptr(src_fp, tp->ctt_name); - kind = LCTF_INFO_KIND(src_fp, tp->ctt_info); - flag = LCTF_INFO_ROOT(src_fp, tp->ctt_info); - vlen = LCTF_INFO_VLEN(src_fp, tp->ctt_info); + name = ctf_type_rname(src_fp, tp); + + ctf_get_ctt_info(src_fp, tp, &kind, &vlen, &flag); switch (kind) { case CTF_K_STRUCT: hp = &dst_fp->ctf_structs; break; case CTF_K_UNION: hp = &dst_fp->ctf_unions; break; case CTF_K_ENUM: hp = &dst_fp->ctf_enums; break; default: hp = &dst_fp->ctf_names; break; } /* * If the source type has a name and is a root type (visible at the * top-level scope), lookup the name in the destination container and * verify that it is of the same kind before we do anything else. */ if ((flag & CTF_ADD_ROOT) && name[0] != '\0' && (hep = ctf_hash_lookup(hp, dst_fp, name, strlen(name))) != NULL) { dst_type = (ctf_id_t)hep->h_type; dst_kind = ctf_type_kind(dst_fp, dst_type); } /* * If an identically named dst_type exists, fail with ECTF_CONFLICT * unless dst_type is a forward declaration and src_type is a struct, * union, or enum (i.e. the definition of the previous forward decl). */ if (dst_type != CTF_ERR && dst_kind != kind) { if (dst_kind != CTF_K_FORWARD || (kind != CTF_K_ENUM && kind != CTF_K_STRUCT && kind != CTF_K_UNION)) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); else dst_type = CTF_ERR; } /* * If the non-empty name was not found in the appropriate hash, search * the list of pending dynamic definitions that are not yet committed. * If a matching name and kind are found, assume this is the type that * we are looking for. This is necessary to permit ctf_add_type() to * operate recursively on entities such as a struct that contains a * pointer member that refers to the same struct type. * * In the case of integer and floating point types, we match using the * type encoding as well - else we may incorrectly return a bitfield * type, for instance. */ if (dst_type == CTF_ERR && name[0] != '\0') { for (dtd = ctf_list_prev(&dst_fp->ctf_dtdefs); dtd != NULL && - CTF_TYPE_TO_INDEX(dtd->dtd_type) > dst_fp->ctf_dtoldid; - dtd = ctf_list_prev(dtd)) { - if (CTF_INFO_KIND(dtd->dtd_data.ctt_info) != kind || - dtd->dtd_name == NULL || + LCTF_TYPE_TO_INDEX(dst_fp, dtd->dtd_type) > + dst_fp->ctf_dtoldid; dtd = ctf_list_prev(dtd)) { + if (LCTF_INFO_KIND(dst_fp, dtd->dtd_data.ctt_info) != + kind || dtd->dtd_name == NULL || strcmp(dtd->dtd_name, name) != 0) continue; if (kind == CTF_K_INTEGER || kind == CTF_K_FLOAT) { if (ctf_type_encoding(src_fp, src_type, &src_en) != 0) continue; if (bcmp(&src_en, &dtd->dtd_u.dtu_enc, sizeof (ctf_encoding_t)) != 0) continue; } return (dtd->dtd_type); } } src.ctb_file = src_fp; src.ctb_type = src_type; src.ctb_dtd = NULL; dst.ctb_file = dst_fp; dst.ctb_type = dst_type; dst.ctb_dtd = NULL; /* * Now perform kind-specific processing. If dst_type is CTF_ERR, then * we add a new type with the same properties as src_type to dst_fp. * If dst_type is not CTF_ERR, then we verify that dst_type has the * same attributes as src_type. We recurse for embedded references. */ switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: if (ctf_type_encoding(src_fp, src_type, &src_en) != 0) return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); /* * This could be a bitfield, and the CTF library assumes * intrinsics will appear before bitfields. Therefore, * try to copy over the intrinsic prior to copying the * bitfield. */ if (dst_type == CTF_ERR && name[0] != '\0' && (hep = ctf_hash_lookup(&src_fp->ctf_names, src_fp, name, strlen(name))) != NULL && src_type != (ctf_id_t)hep->h_type) { if (ctf_type_encoding(src_fp, (ctf_id_t)hep->h_type, &main_en) != 0) { return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); } if (bcmp(&src_en, &main_en, sizeof (ctf_encoding_t)) && ctf_add_type(dst_fp, src_fp, (ctf_id_t)hep->h_type) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ } if (dst_type != CTF_ERR) { if (ctf_type_encoding(dst_fp, dst_type, &dst_en) != 0) return (CTF_ERR); /* errno is set for us */ if (bcmp(&src_en, &dst_en, sizeof (ctf_encoding_t))) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); } else if (kind == CTF_K_INTEGER) { dst_type = ctf_add_integer(dst_fp, flag, name, &src_en); } else dst_type = ctf_add_float(dst_fp, flag, name, &src_en); break; case CTF_K_POINTER: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: src_type = ctf_type_reference(src_fp, src_type); src_type = ctf_add_type(dst_fp, src_fp, src_type); if (src_type == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dst_type = ctf_add_reftype(dst_fp, flag, src_type, kind); break; case CTF_K_ARRAY: if (ctf_array_info(src_fp, src_type, &src_ar) == CTF_ERR) return (ctf_set_errno(dst_fp, ctf_errno(src_fp))); src_ar.ctr_contents = ctf_add_type(dst_fp, src_fp, src_ar.ctr_contents); src_ar.ctr_index = ctf_add_type(dst_fp, src_fp, src_ar.ctr_index); src_ar.ctr_nelems = src_ar.ctr_nelems; if (src_ar.ctr_contents == CTF_ERR || src_ar.ctr_index == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if (dst_type != CTF_ERR) { if (ctf_array_info(dst_fp, dst_type, &dst_ar) != 0) return (CTF_ERR); /* errno is set for us */ if (bcmp(&src_ar, &dst_ar, sizeof (ctf_arinfo_t))) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); } else dst_type = ctf_add_array(dst_fp, flag, &src_ar); break; case CTF_K_FUNCTION: - ctc.ctc_return = ctf_add_type(dst_fp, src_fp, tp->ctt_type); + ctf_get_ctt_index(src_fp, tp, NULL, &type, NULL); + ctc.ctc_return = ctf_add_type(dst_fp, src_fp, type); ctc.ctc_argc = 0; ctc.ctc_flags = 0; if (ctc.ctc_return == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dst_type = ctf_add_function(dst_fp, flag, &ctc, NULL); break; case CTF_K_STRUCT: case CTF_K_UNION: { ctf_dmdef_t *dmd; int errs = 0; if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { /* * Compare the sizes and fields of the two types. * The field comparisons only check the names and * offsets, so this is not perfect but is good enough * for scenarios that we care about. */ if (soucmp(src_fp, src_type, dst_fp, dst_type) != 0) return (CTF_ERR); /* errno is set for us */ break; } /* * Unlike the other cases, copying structs and unions is done * manually so as to avoid repeated lookups in ctf_add_member * and to ensure the exact same member offsets as in src_type. */ dst_type = ctf_add_generic(dst_fp, flag, name, &dtd); if (dst_type == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dst.ctb_type = dst_type; dst.ctb_dtd = dtd; if (ctf_member_iter(src_fp, src_type, membadd, &dst) != 0) errs++; /* increment errs and fail at bottom of case */ - if ((size = ctf_type_size(src_fp, src_type)) > CTF_MAX_SIZE) { - dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; + if ((size = ctf_type_size(src_fp, src_type)) > + LCTF_MAX_SIZE(src_fp)) { + dtd->dtd_data.ctt_size = LCTF_LSIZE_SENT(dst_fp); dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI(size); dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO(size); } else - dtd->dtd_data.ctt_size = (ushort_t)size; + dtd->dtd_data.ctt_size = size; - dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, flag, vlen); + dtd->dtd_data.ctt_info = LCTF_TYPE_INFO(dst_fp, kind, flag, + vlen); /* * Make a final pass through the members changing each dmd_type * (a src_fp type) to an equivalent type in dst_fp. We pass * through all members, leaving any that fail set to CTF_ERR. */ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = ctf_list_next(dmd)) { if ((dmd->dmd_type = ctf_add_type(dst_fp, src_fp, dmd->dmd_type)) == CTF_ERR) errs++; } if (errs) return (CTF_ERR); /* errno is set for us */ /* * Now that we know that we can't fail, we go through and bump * all the reference counts on the member types. */ for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = ctf_list_next(dmd)) ctf_ref_inc(dst_fp, dmd->dmd_type); break; } case CTF_K_ENUM: if (dst_type != CTF_ERR && dst_kind != CTF_K_FORWARD) { if (ctf_enum_iter(src_fp, src_type, enumcmp, &dst) || ctf_enum_iter(dst_fp, dst_type, enumcmp, &src)) return (ctf_set_errno(dst_fp, ECTF_CONFLICT)); } else { dst_type = ctf_add_enum(dst_fp, flag, name); if ((dst.ctb_type = dst_type) == CTF_ERR || ctf_enum_iter(src_fp, src_type, enumadd, &dst)) return (CTF_ERR); /* errno is set for us */ } break; case CTF_K_FORWARD: if (dst_type == CTF_ERR) { dst_type = ctf_add_forward(dst_fp, flag, name, CTF_K_STRUCT); /* assume STRUCT */ } break; case CTF_K_TYPEDEF: src_type = ctf_type_reference(src_fp, src_type); src_type = ctf_add_type(dst_fp, src_fp, src_type); if (src_type == CTF_ERR) return (CTF_ERR); /* errno is set for us */ /* * If dst_type is not CTF_ERR at this point, we should check if * ctf_type_reference(dst_fp, dst_type) != src_type and if so * fail with ECTF_CONFLICT. However, this causes problems with * typedefs that vary based on things like if * _ILP32x then pid_t is int otherwise long. We therefore omit * this check and assume that if the identically named typedef * already exists in dst_fp, it is correct or equivalent. */ if (dst_type == CTF_ERR) { dst_type = ctf_add_typedef(dst_fp, flag, name, src_type); } break; default: return (ctf_set_errno(dst_fp, ECTF_CORRUPT)); } return (dst_type); } diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_decl.c b/cddl/contrib/opensolaris/common/ctf/ctf_decl.c index 6bf57001570f..63d173c15f5f 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_decl.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_decl.c @@ -1,184 +1,187 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * CTF Declaration Stack * * In order to implement ctf_type_name(), we must convert a type graph back * into a C type declaration. Unfortunately, a type graph represents a storage * class ordering of the type whereas a type declaration must obey the C rules * for operator precedence, and the two orderings are frequently in conflict. * For example, consider these CTF type graphs and their C declarations: * * CTF_K_POINTER -> CTF_K_FUNCTION -> CTF_K_INTEGER : int (*)() * CTF_K_POINTER -> CTF_K_ARRAY -> CTF_K_INTEGER : int (*)[] * * In each case, parentheses are used to raise operator * to higher lexical * precedence, so the string form of the C declaration cannot be constructed by * walking the type graph links and forming the string from left to right. * * The functions in this file build a set of stacks from the type graph nodes * corresponding to the C operator precedence levels in the appropriate order. * The code in ctf_type_name() can then iterate over the levels and nodes in * lexical precedence order and construct the final C declaration string. */ #include void ctf_decl_init(ctf_decl_t *cd, char *buf, size_t len) { int i; bzero(cd, sizeof (ctf_decl_t)); for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) cd->cd_order[i] = CTF_PREC_BASE - 1; cd->cd_qualp = CTF_PREC_BASE; cd->cd_ordp = CTF_PREC_BASE; cd->cd_buf = buf; cd->cd_ptr = buf; cd->cd_end = buf + len; } void ctf_decl_fini(ctf_decl_t *cd) { ctf_decl_node_t *cdp, *ndp; int i; for (i = CTF_PREC_BASE; i < CTF_PREC_MAX; i++) { for (cdp = ctf_list_next(&cd->cd_nodes[i]); cdp != NULL; cdp = ndp) { ndp = ctf_list_next(cdp); ctf_free(cdp, sizeof (ctf_decl_node_t)); } } } void ctf_decl_push(ctf_decl_t *cd, ctf_file_t *fp, ctf_id_t type) { ctf_decl_node_t *cdp; ctf_decl_prec_t prec; - uint_t kind, n = 1; + uint_t ctype, kind, n = 1; int is_qual = 0; - const ctf_type_t *tp; + const void *tp; ctf_arinfo_t ar; if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) { cd->cd_err = fp->ctf_errno; return; } - switch (kind = LCTF_INFO_KIND(fp, tp->ctt_info)) { + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + ctf_get_ctt_index(fp, tp, NULL, &ctype, NULL); + + switch (kind) { case CTF_K_ARRAY: (void) ctf_array_info(fp, type, &ar); ctf_decl_push(cd, fp, ar.ctr_contents); n = ar.ctr_nelems; prec = CTF_PREC_ARRAY; break; case CTF_K_TYPEDEF: - if (ctf_strptr(fp, tp->ctt_name)[0] == '\0') { - ctf_decl_push(cd, fp, tp->ctt_type); + if (ctf_type_rname(fp, tp)[0] == '\0') { + ctf_decl_push(cd, fp, ctype); return; } prec = CTF_PREC_BASE; break; case CTF_K_FUNCTION: - ctf_decl_push(cd, fp, tp->ctt_type); + ctf_decl_push(cd, fp, ctype); prec = CTF_PREC_FUNCTION; break; case CTF_K_POINTER: - ctf_decl_push(cd, fp, tp->ctt_type); + ctf_decl_push(cd, fp, ctype); prec = CTF_PREC_POINTER; break; case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: - ctf_decl_push(cd, fp, tp->ctt_type); + ctf_decl_push(cd, fp, ctype); prec = cd->cd_qualp; is_qual++; break; default: prec = CTF_PREC_BASE; } if ((cdp = ctf_alloc(sizeof (ctf_decl_node_t))) == NULL) { cd->cd_err = EAGAIN; return; } cdp->cd_type = type; cdp->cd_kind = kind; cdp->cd_n = n; if (ctf_list_next(&cd->cd_nodes[prec]) == NULL) cd->cd_order[prec] = cd->cd_ordp++; /* * Reset cd_qualp to the highest precedence level that we've seen so * far that can be qualified (CTF_PREC_BASE or CTF_PREC_POINTER). */ if (prec > cd->cd_qualp && prec < CTF_PREC_ARRAY) cd->cd_qualp = prec; /* * C array declarators are ordered inside out so prepend them. Also by * convention qualifiers of base types precede the type specifier (e.g. * const int vs. int const) even though the two forms are equivalent. */ if (kind == CTF_K_ARRAY || (is_qual && prec == CTF_PREC_BASE)) ctf_list_prepend(&cd->cd_nodes[prec], cdp); else ctf_list_append(&cd->cd_nodes[prec], cdp); } /*PRINTFLIKE2*/ void ctf_decl_sprintf(ctf_decl_t *cd, const char *format, ...) { size_t len = (size_t)(cd->cd_end - cd->cd_ptr); va_list ap; size_t n; va_start(ap, format); n = vsnprintf(cd->cd_ptr, len, format, ap); va_end(ap); cd->cd_ptr += MIN(n, len); cd->cd_len += n; } diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_hash.c b/cddl/contrib/opensolaris/common/ctf/ctf_hash.c index b10a7618f66e..5a36fbbd88cf 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_hash.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_hash.c @@ -1,178 +1,178 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include -static const ushort_t _CTF_EMPTY[1] = { 0 }; +static const uint_t _CTF_EMPTY[1] = { 0 }; int ctf_hash_create(ctf_hash_t *hp, ulong_t nelems) { if (nelems > USHRT_MAX) return (EOVERFLOW); /* * If the hash table is going to be empty, don't bother allocating any * memory and make the only bucket point to a zero so lookups fail. */ if (nelems == 0) { bzero(hp, sizeof (ctf_hash_t)); - hp->h_buckets = (ushort_t *)_CTF_EMPTY; + hp->h_buckets = (uint_t *)_CTF_EMPTY; hp->h_nbuckets = 1; return (0); } hp->h_nbuckets = 211; /* use a prime number of hash buckets */ hp->h_nelems = nelems + 1; /* we use index zero as a sentinel */ hp->h_free = 1; /* first free element is index 1 */ - hp->h_buckets = ctf_alloc(sizeof (ushort_t) * hp->h_nbuckets); + hp->h_buckets = ctf_alloc(sizeof (uint_t) * hp->h_nbuckets); hp->h_chains = ctf_alloc(sizeof (ctf_helem_t) * hp->h_nelems); if (hp->h_buckets == NULL || hp->h_chains == NULL) { ctf_hash_destroy(hp); return (EAGAIN); } - bzero(hp->h_buckets, sizeof (ushort_t) * hp->h_nbuckets); + bzero(hp->h_buckets, sizeof (uint_t) * hp->h_nbuckets); bzero(hp->h_chains, sizeof (ctf_helem_t) * hp->h_nelems); return (0); } uint_t ctf_hash_size(const ctf_hash_t *hp) { return (hp->h_nelems ? hp->h_nelems - 1 : 0); } static ulong_t ctf_hash_compute(const char *key, size_t len) { ulong_t g, h = 0; const char *p, *q = key + len; size_t n = 0; for (p = key; p < q; p++, n++) { h = (h << 4) + *p; if ((g = (h & 0xf0000000)) != 0) { h ^= (g >> 24); h ^= g; } } return (h); } int -ctf_hash_insert(ctf_hash_t *hp, ctf_file_t *fp, ushort_t type, uint_t name) +ctf_hash_insert(ctf_hash_t *hp, ctf_file_t *fp, uint_t type, uint_t name) { ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID(name)]; const char *str = ctsp->cts_strs + CTF_NAME_OFFSET(name); ctf_helem_t *hep = &hp->h_chains[hp->h_free]; ulong_t h; if (type == 0) return (EINVAL); if (hp->h_free >= hp->h_nelems) return (EOVERFLOW); if (ctsp->cts_strs == NULL) return (ECTF_STRTAB); if (ctsp->cts_len <= CTF_NAME_OFFSET(name)) return (ECTF_BADNAME); if (str[0] == '\0') return (0); /* just ignore empty strings on behalf of caller */ hep->h_name = name; hep->h_type = type; h = ctf_hash_compute(str, strlen(str)) % hp->h_nbuckets; hep->h_next = hp->h_buckets[h]; hp->h_buckets[h] = hp->h_free++; return (0); } /* * Wrapper for ctf_hash_lookup/ctf_hash_insert: if the key is already in the * hash, override the previous definition with this new official definition. * If the key is not present, then call ctf_hash_insert() and hash it in. */ int -ctf_hash_define(ctf_hash_t *hp, ctf_file_t *fp, ushort_t type, uint_t name) +ctf_hash_define(ctf_hash_t *hp, ctf_file_t *fp, uint_t type, uint_t name) { const char *str = ctf_strptr(fp, name); ctf_helem_t *hep = ctf_hash_lookup(hp, fp, str, strlen(str)); if (hep == NULL) return (ctf_hash_insert(hp, fp, type, name)); hep->h_type = type; return (0); } ctf_helem_t * ctf_hash_lookup(ctf_hash_t *hp, ctf_file_t *fp, const char *key, size_t len) { ctf_helem_t *hep; ctf_strs_t *ctsp; const char *str; - ushort_t i; + uint_t i; ulong_t h = ctf_hash_compute(key, len) % hp->h_nbuckets; for (i = hp->h_buckets[h]; i != 0; i = hep->h_next) { hep = &hp->h_chains[i]; ctsp = &fp->ctf_str[CTF_NAME_STID(hep->h_name)]; str = ctsp->cts_strs + CTF_NAME_OFFSET(hep->h_name); if (strncmp(key, str, len) == 0 && str[len] == '\0') return (hep); } return (NULL); } void ctf_hash_destroy(ctf_hash_t *hp) { if (hp->h_buckets != NULL && hp->h_nbuckets != 1) { - ctf_free(hp->h_buckets, sizeof (ushort_t) * hp->h_nbuckets); + ctf_free(hp->h_buckets, sizeof (uint_t) * hp->h_nbuckets); hp->h_buckets = NULL; } if (hp->h_chains != NULL) { ctf_free(hp->h_chains, sizeof (ctf_helem_t) * hp->h_nelems); hp->h_chains = NULL; } } diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_impl.h b/cddl/contrib/opensolaris/common/ctf/ctf_impl.h index dd6167856074..774eff1380fa 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_impl.h +++ b/cddl/contrib/opensolaris/common/ctf/ctf_impl.h @@ -1,340 +1,373 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ #ifndef _CTF_IMPL_H #define _CTF_IMPL_H #include #include #include #include #ifdef _KERNEL #include #include #include #define isspace(c) \ ((c) == ' ' || (c) == '\t' || (c) == '\n' || \ (c) == '\r' || (c) == '\f' || (c) == '\v') #define MAP_FAILED ((void *)-1) #else /* _KERNEL */ #include #include #include #include #include #include #endif /* _KERNEL */ #ifdef __cplusplus extern "C" { #endif typedef struct ctf_helem { uint_t h_name; /* reference to name in string table */ - ushort_t h_type; /* corresponding type ID number */ - ushort_t h_next; /* index of next element in hash chain */ + uint_t h_type; /* corresponding type ID number */ + uint_t h_next; /* index of next element in hash chain */ } ctf_helem_t; typedef struct ctf_hash { - ushort_t *h_buckets; /* hash bucket array (chain indices) */ + uint_t *h_buckets; /* hash bucket array (chain indices) */ ctf_helem_t *h_chains; /* hash chains buffer */ - ushort_t h_nbuckets; /* number of elements in bucket array */ - ushort_t h_nelems; /* number of elements in hash table */ + uint_t h_nbuckets; /* number of elements in bucket array */ + uint_t h_nelems; /* number of elements in hash table */ uint_t h_free; /* index of next free hash element */ } ctf_hash_t; typedef struct ctf_strs { const char *cts_strs; /* base address of string table */ size_t cts_len; /* size of string table in bytes */ } ctf_strs_t; typedef struct ctf_dmodel { const char *ctd_name; /* data model name */ int ctd_code; /* data model code */ size_t ctd_pointer; /* size of void * in bytes */ size_t ctd_char; /* size of char in bytes */ size_t ctd_short; /* size of short in bytes */ size_t ctd_int; /* size of int in bytes */ size_t ctd_long; /* size of long in bytes */ } ctf_dmodel_t; typedef struct ctf_lookup { const char *ctl_prefix; /* string prefix for this lookup */ size_t ctl_len; /* length of prefix string in bytes */ ctf_hash_t *ctl_hash; /* pointer to hash table for lookup */ } ctf_lookup_t; typedef struct ctf_fileops { - ushort_t (*ctfo_get_kind)(ushort_t); - ushort_t (*ctfo_get_root)(ushort_t); - ushort_t (*ctfo_get_vlen)(ushort_t); + uint_t (*ctfo_get_kind)(uint_t); + uint_t (*ctfo_get_root)(uint_t); + uint_t (*ctfo_get_vlen)(uint_t); + uint_t (*ctfo_get_max_vlen)(void); + uint_t (*ctfo_get_max_size)(void); + uint_t (*ctfo_get_max_type)(void); + uint_t (*ctfo_get_lsize_sent)(void); + uint_t (*ctfo_get_lstruct_thresh)(void); + + uint_t (*ctfo_type_info)(uint_t, uint_t, uint_t); + int (*ctfo_type_isparent)(uint_t); + int (*ctfo_type_ischild)(uint_t); + uint_t (*ctfo_type_to_index)(uint_t); + uint_t (*ctfo_index_to_type)(uint_t, uint_t); } ctf_fileops_t; typedef struct ctf_list { struct ctf_list *l_prev; /* previous pointer or tail pointer */ struct ctf_list *l_next; /* next pointer or head pointer */ } ctf_list_t; typedef enum { CTF_PREC_BASE, CTF_PREC_POINTER, CTF_PREC_ARRAY, CTF_PREC_FUNCTION, CTF_PREC_MAX } ctf_decl_prec_t; typedef struct ctf_decl_node { ctf_list_t cd_list; /* linked list pointers */ ctf_id_t cd_type; /* type identifier */ uint_t cd_kind; /* type kind */ uint_t cd_n; /* type dimension if array */ } ctf_decl_node_t; typedef struct ctf_decl { ctf_list_t cd_nodes[CTF_PREC_MAX]; /* declaration node stacks */ int cd_order[CTF_PREC_MAX]; /* storage order of decls */ ctf_decl_prec_t cd_qualp; /* qualifier precision */ ctf_decl_prec_t cd_ordp; /* ordered precision */ char *cd_buf; /* buffer for output */ char *cd_ptr; /* buffer location */ char *cd_end; /* buffer limit */ size_t cd_len; /* buffer space required */ int cd_err; /* saved error value */ } ctf_decl_t; typedef struct ctf_dmdef { ctf_list_t dmd_list; /* list forward/back pointers */ char *dmd_name; /* name of this member */ ctf_id_t dmd_type; /* type of this member (for sou) */ ulong_t dmd_offset; /* offset of this member in bits (for sou) */ int dmd_value; /* value of this member (for enum) */ } ctf_dmdef_t; typedef struct ctf_dtdef { ctf_list_t dtd_list; /* list forward/back pointers */ struct ctf_dtdef *dtd_hash; /* hash chain pointer for ctf_dthash */ char *dtd_name; /* name associated with definition (if any) */ ctf_id_t dtd_type; /* type identifier for this definition */ - ctf_type_t dtd_data; /* type node (see ) */ + struct ctf_type_v3 dtd_data; /* type node (see ) */ int dtd_ref; /* recfount for dyanmic types */ union { ctf_list_t dtu_members; /* struct, union, or enum */ ctf_arinfo_t dtu_arr; /* array */ ctf_encoding_t dtu_enc; /* integer or float */ ctf_id_t *dtu_argv; /* function */ } dtd_u; } ctf_dtdef_t; typedef struct ctf_bundle { ctf_file_t *ctb_file; /* CTF container handle */ ctf_id_t ctb_type; /* CTF type identifier */ ctf_dtdef_t *ctb_dtd; /* CTF dynamic type definition (if any) */ } ctf_bundle_t; /* * The ctf_file is the structure used to represent a CTF container to library * clients, who see it only as an opaque pointer. Modifications can therefore * be made freely to this structure without regard to client versioning. The * ctf_file_t typedef appears in and declares a forward tag. * * NOTE: ctf_update() requires that everything inside of ctf_file either be an * immediate value, a pointer to dynamically allocated data *outside* of the * ctf_file itself, or a pointer to statically allocated data. If you add a * pointer to ctf_file that points to something within the ctf_file itself, * you must make corresponding changes to ctf_update(). */ struct ctf_file { const ctf_fileops_t *ctf_fileops; /* version-specific file operations */ ctf_sect_t ctf_data; /* CTF data from object file */ ctf_sect_t ctf_symtab; /* symbol table from object file */ ctf_sect_t ctf_strtab; /* string table from object file */ ctf_hash_t ctf_structs; /* hash table of struct types */ ctf_hash_t ctf_unions; /* hash table of union types */ ctf_hash_t ctf_enums; /* hash table of enum types */ ctf_hash_t ctf_names; /* hash table of remaining type names */ ctf_lookup_t ctf_lookups[5]; /* pointers to hashes for name lookup */ ctf_strs_t ctf_str[2]; /* array of string table base and bounds */ const uchar_t *ctf_base; /* base of CTF header + uncompressed buffer */ const uchar_t *ctf_buf; /* uncompressed CTF data buffer */ size_t ctf_size; /* size of CTF header + uncompressed data */ uint_t *ctf_sxlate; /* translation table for symtab entries */ ulong_t ctf_nsyms; /* number of entries in symtab xlate table */ uint_t *ctf_txlate; /* translation table for type IDs */ - ushort_t *ctf_ptrtab; /* translation table for pointer-to lookups */ + uint_t *ctf_ptrtab; /* translation table for pointer-to lookups */ ulong_t ctf_typemax; /* maximum valid type ID number */ const ctf_dmodel_t *ctf_dmodel; /* data model pointer (see above) */ struct ctf_file *ctf_parent; /* parent CTF container (if any) */ const char *ctf_parlabel; /* label in parent container (if any) */ const char *ctf_parname; /* basename of parent (if any) */ uint_t ctf_refcnt; /* reference count (for parent links) */ uint_t ctf_flags; /* libctf flags (see below) */ int ctf_errno; /* error code for most recent error */ int ctf_version; /* CTF data version */ + size_t ctf_idwidth; /* Size, in bytes, of a type ID */ ctf_dtdef_t **ctf_dthash; /* hash of dynamic type definitions */ ulong_t ctf_dthashlen; /* size of dynamic type hash bucket array */ ctf_list_t ctf_dtdefs; /* list of dynamic type definitions */ size_t ctf_dtstrlen; /* total length of dynamic type strings */ ulong_t ctf_dtnextid; /* next dynamic type id to assign */ ulong_t ctf_dtoldid; /* oldest id that has been committed */ void *ctf_specific; /* data for ctf_get/setspecific */ }; #define LCTF_INDEX_TO_TYPEPTR(fp, i) \ - ((ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)])) + ((void *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)])) #define LCTF_INFO_KIND(fp, info) ((fp)->ctf_fileops->ctfo_get_kind(info)) #define LCTF_INFO_ROOT(fp, info) ((fp)->ctf_fileops->ctfo_get_root(info)) #define LCTF_INFO_VLEN(fp, info) ((fp)->ctf_fileops->ctfo_get_vlen(info)) +#define LCTF_MAX_VLEN(fp) ((fp)->ctf_fileops->ctfo_get_max_vlen()) +#define LCTF_MAX_SIZE(fp) ((fp)->ctf_fileops->ctfo_get_max_size()) +#define LCTF_MAX_TYPE(fp) ((fp)->ctf_fileops->ctfo_get_max_type()) +#define LCTF_LSIZE_SENT(fp) \ + ((fp)->ctf_fileops->ctfo_get_lsize_sent()) +#define LCTF_LSTRUCT_THRESH(fp) \ + ((fp)->ctf_fileops->ctfo_get_lstruct_thresh()) + +#define LCTF_TYPE_INFO(fp, k, r, l) ((fp)->ctf_fileops->ctfo_type_info(k, r, l)) +#define LCTF_TYPE_ISPARENT(fp, id) ((fp)->ctf_fileops->ctfo_type_isparent(id)) +#define LCTF_TYPE_ISCHILD(fp, id) ((fp)->ctf_fileops->ctfo_type_ischild(id)) +#define LCTF_TYPE_TO_INDEX(fp, t) ((fp)->ctf_fileops->ctfo_type_to_index(t)) +#define LCTF_INDEX_TO_TYPE(fp, id, c) ((fp)->ctf_fileops->ctfo_index_to_type(id, c)) #define LCTF_MMAP 0x0001 /* libctf should munmap buffers on close */ #define LCTF_CHILD 0x0002 /* CTF container is a child */ #define LCTF_RDWR 0x0004 /* CTF container is writable */ #define LCTF_DIRTY 0x0008 /* CTF container has been modified */ #define ECTF_BASE 1000 /* base value for libctf errnos */ enum { ECTF_FMT = ECTF_BASE, /* file is not in CTF or ELF format */ ECTF_ELFVERS, /* ELF version is more recent than libctf */ ECTF_CTFVERS, /* CTF version is more recent than libctf */ ECTF_ENDIAN, /* data is different endian-ness than lib */ ECTF_SYMTAB, /* symbol table uses invalid entry size */ ECTF_SYMBAD, /* symbol table data buffer invalid */ ECTF_STRBAD, /* string table data buffer invalid */ ECTF_CORRUPT, /* file data corruption detected */ ECTF_NOCTFDATA, /* ELF file does not contain CTF data */ ECTF_NOCTFBUF, /* buffer does not contain CTF data */ ECTF_NOSYMTAB, /* symbol table data is not available */ ECTF_NOPARENT, /* parent CTF container is not available */ ECTF_DMODEL, /* data model mismatch */ ECTF_MMAP, /* failed to mmap a data section */ ECTF_ZMISSING, /* decompression library not installed */ ECTF_ZINIT, /* failed to initialize decompression library */ ECTF_ZALLOC, /* failed to allocate decompression buffer */ ECTF_DECOMPRESS, /* failed to decompress CTF data */ ECTF_STRTAB, /* string table for this string is missing */ ECTF_BADNAME, /* string offset is corrupt w.r.t. strtab */ ECTF_BADID, /* invalid type ID number */ ECTF_NOTSOU, /* type is not a struct or union */ ECTF_NOTENUM, /* type is not an enum */ ECTF_NOTSUE, /* type is not a struct, union, or enum */ ECTF_NOTINTFP, /* type is not an integer or float */ ECTF_NOTARRAY, /* type is not an array */ ECTF_NOTREF, /* type does not reference another type */ ECTF_NAMELEN, /* buffer is too small to hold type name */ ECTF_NOTYPE, /* no type found corresponding to name */ ECTF_SYNTAX, /* syntax error in type name */ ECTF_NOTFUNC, /* symtab entry does not refer to a function */ ECTF_NOFUNCDAT, /* no func info available for function */ ECTF_NOTDATA, /* symtab entry does not refer to a data obj */ ECTF_NOTYPEDAT, /* no type info available for object */ ECTF_NOLABEL, /* no label found corresponding to name */ ECTF_NOLABELDATA, /* file does not contain any labels */ ECTF_NOTSUP, /* feature not supported */ ECTF_NOENUMNAM, /* enum element name not found */ ECTF_NOMEMBNAM, /* member name not found */ ECTF_RDONLY, /* CTF container is read-only */ ECTF_DTFULL, /* CTF type is full (no more members allowed) */ ECTF_FULL, /* CTF container is full */ ECTF_DUPMEMBER, /* duplicate member name definition */ ECTF_CONFLICT, /* conflicting type definition present */ ECTF_REFERENCED, /* type has outstanding references */ ECTF_NOTDYN /* type is not a dynamic type */ }; -extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const ctf_type_t *, - ssize_t *, ssize_t *); +extern void ctf_get_ctt_index(const ctf_file_t *fp, const void *v, + uint_t *indexp, uint_t *typep, int *ischildp); +extern ssize_t ctf_get_ctt_size(const ctf_file_t *, const void *v, ssize_t *, + ssize_t *); +extern void ctf_get_ctt_info(const ctf_file_t *, const void *v, uint_t *kind, + uint_t *vlen, int *isroot); -extern const ctf_type_t *ctf_lookup_by_id(ctf_file_t **, ctf_id_t); +extern void ctf_get_ctm_info(const ctf_file_t *fp, const void *v, size_t sz, + size_t *incrementp, uint_t *typep, ulong_t *offsetp, const char **namep); + +extern const void *ctf_lookup_by_id(ctf_file_t **, ctf_id_t); +extern const char *ctf_type_rname(ctf_file_t *, const void *); extern int ctf_hash_create(ctf_hash_t *, ulong_t); -extern int ctf_hash_insert(ctf_hash_t *, ctf_file_t *, ushort_t, uint_t); -extern int ctf_hash_define(ctf_hash_t *, ctf_file_t *, ushort_t, uint_t); +extern int ctf_hash_insert(ctf_hash_t *, ctf_file_t *, uint_t, uint_t); +extern int ctf_hash_define(ctf_hash_t *, ctf_file_t *, uint_t, uint_t); extern ctf_helem_t *ctf_hash_lookup(ctf_hash_t *, ctf_file_t *, const char *, size_t); extern uint_t ctf_hash_size(const ctf_hash_t *); extern void ctf_hash_destroy(ctf_hash_t *); #define ctf_list_prev(elem) ((void *)(((ctf_list_t *)(elem))->l_prev)) #define ctf_list_next(elem) ((void *)(((ctf_list_t *)(elem))->l_next)) extern void ctf_list_append(ctf_list_t *, void *); extern void ctf_list_prepend(ctf_list_t *, void *); extern void ctf_list_delete(ctf_list_t *, void *); extern void ctf_dtd_insert(ctf_file_t *, ctf_dtdef_t *); extern void ctf_dtd_delete(ctf_file_t *, ctf_dtdef_t *); extern ctf_dtdef_t *ctf_dtd_lookup(ctf_file_t *, ctf_id_t); extern void ctf_decl_init(ctf_decl_t *, char *, size_t); extern void ctf_decl_fini(ctf_decl_t *); extern void ctf_decl_push(ctf_decl_t *, ctf_file_t *, ctf_id_t); extern void ctf_decl_sprintf(ctf_decl_t *, const char *, ...); extern const char *ctf_strraw(const ctf_file_t *, uint_t); extern const char *ctf_strptr(const ctf_file_t *, uint_t); extern ctf_file_t *ctf_set_open_errno(int *, int); extern long ctf_set_errno(ctf_file_t *, int); extern const void *ctf_sect_mmap(ctf_sect_t *, int); extern void ctf_sect_munmap(const ctf_sect_t *); extern void *ctf_data_alloc(size_t); extern void ctf_data_free(void *, size_t); extern void ctf_data_protect(void *, size_t); extern void *ctf_alloc(size_t); extern void ctf_free(void *, size_t); extern char *ctf_strdup(const char *); extern const char *ctf_strerror(int); extern void ctf_dprintf(const char *, ...); extern void *ctf_zopen(int *); extern const char _CTF_SECTION[]; /* name of CTF ELF section */ extern const char _CTF_NULLSTR[]; /* empty string */ extern int _libctf_version; /* library client version */ extern int _libctf_debug; /* debugging messages enabled */ #ifdef __cplusplus } #endif #endif /* _CTF_IMPL_H */ diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c b/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c index cd9c71436938..e822e22f634c 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_lookup.c @@ -1,316 +1,322 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include /* * Compare the given input string and length against a table of known C storage * qualifier keywords. We just ignore these in ctf_lookup_by_name, below. To * do this quickly, we use a pre-computed Perfect Hash Function similar to the * technique originally described in the classic paper: * * R.J. Cichelli, "Minimal Perfect Hash Functions Made Simple", * Communications of the ACM, Volume 23, Issue 1, January 1980, pp. 17-19. * * For an input string S of length N, we use hash H = S[N - 1] + N - 105, which * for the current set of qualifiers yields a unique H in the range [0 .. 20]. * The hash can be modified when the keyword set changes as necessary. We also * store the length of each keyword and check it prior to the final strcmp(). */ static int isqualifier(const char *s, size_t len) { static const struct qual { const char *q_name; size_t q_len; } qhash[] = { { "static", 6 }, { "", 0 }, { "", 0 }, { "", 0 }, { "volatile", 8 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "auto", 4 }, { "extern", 6 }, { "", 0 }, { "", 0 }, { "", 0 }, { "", 0 }, { "const", 5 }, { "register", 8 }, { "", 0 }, { "restrict", 8 }, { "_Restrict", 9 } }; int h = s[len - 1] + (int)len - 105; const struct qual *qp; if (h < 0 || h >= sizeof (qhash) / sizeof (qhash[0])) return (0); qp = &qhash[h]; return (len == qp->q_len && strncmp(qp->q_name, s, qp->q_len) == 0); } /* * Attempt to convert the given C type name into the corresponding CTF type ID. * It is not possible to do complete and proper conversion of type names * without implementing a more full-fledged parser, which is necessary to * handle things like types that are function pointers to functions that * have arguments that are function pointers, and fun stuff like that. * Instead, this function implements a very simple conversion algorithm that * finds the things that we actually care about: structs, unions, enums, * integers, floats, typedefs, and pointers to any of these named types. */ ctf_id_t ctf_lookup_by_name(ctf_file_t *fp, const char *name) { static const char delimiters[] = " \t\n\r\v\f*"; const ctf_lookup_t *lp; const ctf_helem_t *hp; const char *p, *q, *end; ctf_id_t type = 0; ctf_id_t ntype, ptype; if (name == NULL) return (ctf_set_errno(fp, EINVAL)); for (p = name, end = name + strlen(name); *p != '\0'; p = q) { while (isspace(*p)) p++; /* skip leading ws */ if (p == end) break; if ((q = strpbrk(p + 1, delimiters)) == NULL) q = end; /* compare until end */ if (*p == '*') { /* * Find a pointer to type by looking in fp->ctf_ptrtab. * If we can't find a pointer to the given type, see if * we can compute a pointer to the type resulting from * resolving the type down to its base type and use * that instead. This helps with cases where the CTF * data includes "struct foo *" but not "foo_t *" and * the user tries to access "foo_t *" in the debugger. */ - ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]; + ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX(fp, type)]; if (ntype == 0) { ntype = ctf_type_resolve(fp, type); if (ntype == CTF_ERR || (ntype = fp->ctf_ptrtab[ - CTF_TYPE_TO_INDEX(ntype)]) == 0) { + LCTF_TYPE_TO_INDEX(fp, ntype)]) == 0) { (void) ctf_set_errno(fp, ECTF_NOTYPE); goto err; } } - type = CTF_INDEX_TO_TYPE(ntype, + type = LCTF_INDEX_TO_TYPE(fp, ntype, (fp->ctf_flags & LCTF_CHILD)); q = p + 1; continue; } if (isqualifier(p, (size_t)(q - p))) continue; /* skip qualifier keyword */ for (lp = fp->ctf_lookups; lp->ctl_prefix != NULL; lp++) { if (lp->ctl_prefix[0] == '\0' || ((size_t)(q - p) >= lp->ctl_len && strncmp(p, lp->ctl_prefix, (size_t)(q - p)) == 0)) { for (p += lp->ctl_len; isspace(*p); p++) continue; /* skip prefix and next ws */ if ((q = strchr(p, '*')) == NULL) q = end; /* compare until end */ while (isspace(q[-1])) q--; /* exclude trailing ws */ if ((hp = ctf_hash_lookup(lp->ctl_hash, fp, p, (size_t)(q - p))) == NULL) { (void) ctf_set_errno(fp, ECTF_NOTYPE); goto err; } type = hp->h_type; break; } } if (lp->ctl_prefix == NULL) { (void) ctf_set_errno(fp, ECTF_NOTYPE); goto err; } } if (*p != '\0' || type == 0) return (ctf_set_errno(fp, ECTF_SYNTAX)); return (type); err: if (fp->ctf_parent != NULL && (ptype = ctf_lookup_by_name(fp->ctf_parent, name)) != CTF_ERR) return (ptype); return (CTF_ERR); } /* * Given a symbol table index, return the type of the data object described * by the corresponding entry in the symbol table. */ ctf_id_t ctf_lookup_by_symbol(ctf_file_t *fp, ulong_t symidx) { const ctf_sect_t *sp = &fp->ctf_symtab; ctf_id_t type; if (sp->cts_data == NULL) return (ctf_set_errno(fp, ECTF_NOSYMTAB)); if (symidx >= fp->ctf_nsyms) return (ctf_set_errno(fp, EINVAL)); if (sp->cts_entsize == sizeof (Elf32_Sym)) { const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx; if (ELF32_ST_TYPE(symp->st_info) != STT_OBJECT) return (ctf_set_errno(fp, ECTF_NOTDATA)); } else { const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx; if (ELF64_ST_TYPE(symp->st_info) != STT_OBJECT) return (ctf_set_errno(fp, ECTF_NOTDATA)); } if (fp->ctf_sxlate[symidx] == -1u) return (ctf_set_errno(fp, ECTF_NOTYPEDAT)); - type = *(ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]); + type = *(uint_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]); if (type == 0) return (ctf_set_errno(fp, ECTF_NOTYPEDAT)); return (type); } /* * Return the pointer to the internal CTF type data corresponding to the * given type ID. If the ID is invalid, the function returns NULL. * This function is not exported outside of the library. */ -const ctf_type_t * +const void * ctf_lookup_by_id(ctf_file_t **fpp, ctf_id_t type) { ctf_file_t *fp = *fpp; /* caller passes in starting CTF container */ - if ((fp->ctf_flags & LCTF_CHILD) && CTF_TYPE_ISPARENT(type) && - (fp = fp->ctf_parent) == NULL) { - (void) ctf_set_errno(*fpp, ECTF_NOPARENT); - return (NULL); + if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT(fp, type)) { + if (fp->ctf_parent == NULL) { + (void) ctf_set_errno(*fpp, ECTF_NOPARENT); + return (NULL); + } + + /* The parent may be using a different CTF version. */ + type = LCTF_TYPE_TO_INDEX(fp, type); + fp = fp->ctf_parent; + } else { + type = LCTF_TYPE_TO_INDEX(fp, type); } - type = CTF_TYPE_TO_INDEX(type); if (type > 0 && type <= fp->ctf_typemax) { *fpp = fp; /* function returns ending CTF container */ return (LCTF_INDEX_TO_TYPEPTR(fp, type)); } (void) ctf_set_errno(fp, ECTF_BADID); return (NULL); } /* * Given a symbol table index, return the info for the function described * by the corresponding entry in the symbol table. */ int ctf_func_info(ctf_file_t *fp, ulong_t symidx, ctf_funcinfo_t *fip) { const ctf_sect_t *sp = &fp->ctf_symtab; - const ushort_t *dp; - ushort_t info, kind, n; + const uint_t *dp; + uint_t info, kind, n; if (sp->cts_data == NULL) return (ctf_set_errno(fp, ECTF_NOSYMTAB)); if (symidx >= fp->ctf_nsyms) return (ctf_set_errno(fp, EINVAL)); if (sp->cts_entsize == sizeof (Elf32_Sym)) { const Elf32_Sym *symp = (Elf32_Sym *)sp->cts_data + symidx; if (ELF32_ST_TYPE(symp->st_info) != STT_FUNC) return (ctf_set_errno(fp, ECTF_NOTFUNC)); } else { const Elf64_Sym *symp = (Elf64_Sym *)sp->cts_data + symidx; if (ELF64_ST_TYPE(symp->st_info) != STT_FUNC) return (ctf_set_errno(fp, ECTF_NOTFUNC)); } if (fp->ctf_sxlate[symidx] == -1u) return (ctf_set_errno(fp, ECTF_NOFUNCDAT)); - dp = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]); + dp = (uint_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]); info = *dp++; kind = LCTF_INFO_KIND(fp, info); n = LCTF_INFO_VLEN(fp, info); if (kind == CTF_K_UNKNOWN && n == 0) return (ctf_set_errno(fp, ECTF_NOFUNCDAT)); if (kind != CTF_K_FUNCTION) return (ctf_set_errno(fp, ECTF_CORRUPT)); fip->ctc_return = *dp++; fip->ctc_argc = n; fip->ctc_flags = 0; if (n != 0 && dp[n - 1] == 0) { fip->ctc_flags |= CTF_FUNC_VARARG; fip->ctc_argc--; } return (0); } /* * Given a symbol table index, return the arguments for the function described * by the corresponding entry in the symbol table. */ int ctf_func_args(ctf_file_t *fp, ulong_t symidx, uint_t argc, ctf_id_t *argv) { - const ushort_t *dp; + const uint_t *dp; ctf_funcinfo_t f; if (ctf_func_info(fp, symidx, &f) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ /* - * The argument data is two ushort_t's past the translation table + * The argument data is two uint_t's past the translation table * offset: one for the function info, and one for the return type. */ - dp = (ushort_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]) + 2; + dp = (uint_t *)((uintptr_t)fp->ctf_buf + fp->ctf_sxlate[symidx]) + 2; for (argc = MIN(argc, f.ctc_argc); argc != 0; argc--) *argv++ = *dp++; return (0); } diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_open.c b/cddl/contrib/opensolaris/common/ctf/ctf_open.c index 5ab06890d7f1..cdc3e2f028fe 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_open.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_open.c @@ -1,1008 +1,1205 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Copyright (c) 2013, Joyent, Inc. All rights reserved. */ #include #include #include static const ctf_dmodel_t _libctf_models[] = { { "ILP32", CTF_MODEL_ILP32, 4, 1, 2, 4, 4 }, { "LP64", CTF_MODEL_LP64, 8, 1, 2, 4, 8 }, { NULL, 0, 0, 0, 0, 0, 0 } }; const char _CTF_SECTION[] = ".SUNW_ctf"; const char _CTF_NULLSTR[] = ""; int _libctf_version = CTF_VERSION; /* library client version */ int _libctf_debug = 0; /* debugging messages enabled */ -static ushort_t -get_kind_v2(ushort_t info) +static uint_t +get_kind_v2(uint_t info) { - return (CTF_INFO_KIND(info)); + return (CTF_V2_INFO_KIND((ushort_t)info)); } -static ushort_t -get_root_v2(ushort_t info) +static uint_t +get_root_v2(uint_t info) { - return (CTF_INFO_ISROOT(info)); + return (CTF_V2_INFO_ISROOT((ushort_t)info)); } -static ushort_t -get_vlen_v2(ushort_t info) +static uint_t +get_vlen_v2(uint_t info) { - return (CTF_INFO_VLEN(info)); + return (CTF_V2_INFO_VLEN((ushort_t)info)); } +static uint_t +get_max_vlen_v2(void) +{ + return (CTF_V2_MAX_VLEN); +} + +static uint_t +get_max_size_v2(void) +{ + return (CTF_V2_MAX_SIZE); +} + +static uint_t +get_max_type_v2(void) +{ + return (CTF_V2_MAX_TYPE); +} + +static uint_t +get_lsize_sent_v2(void) +{ + return (CTF_V2_LSIZE_SENT); +} + +static uint_t +get_lstruct_thresh_v2(void) +{ + return (CTF_V2_LSTRUCT_THRESH); +} + +static uint_t +type_info_v2(uint_t kind, uint_t isroot, uint_t len) +{ + return (CTF_V2_TYPE_INFO(kind, isroot, len)); +} + +static int +type_isparent_v2(uint_t id) +{ + return (CTF_V2_TYPE_ISPARENT(id)); +} + +static int +type_ischild_v2(uint_t id) +{ + return (CTF_V2_TYPE_ISCHILD(id)); +} + +static uint_t +type_to_index_v2(uint_t t) +{ + return (CTF_V2_TYPE_TO_INDEX(t)); +} + +static uint_t +index_to_type_v2(uint_t id, uint_t child) +{ + return (CTF_V2_INDEX_TO_TYPE(id, child)); +} + +static uint_t +get_kind_v3(uint_t info) +{ + return (CTF_V3_INFO_KIND(info)); +} + +static uint_t +get_root_v3(uint_t info) +{ + return (CTF_V3_INFO_ISROOT(info)); +} + +static uint_t +get_vlen_v3(uint_t info) +{ + return (CTF_V3_INFO_VLEN(info)); +} + +static uint_t +get_max_vlen_v3(void) +{ + return (CTF_V3_MAX_VLEN); +} + +static uint_t +get_max_size_v3(void) +{ + return (CTF_V3_MAX_SIZE); +} + +static uint_t +get_max_type_v3(void) +{ + return (CTF_V3_MAX_TYPE); +} + +static uint_t +get_lsize_sent_v3(void) +{ + return (CTF_V3_LSIZE_SENT); +} + +static uint_t +get_lstruct_thresh_v3(void) +{ + return (CTF_V3_LSTRUCT_THRESH); +} + +static uint_t +type_info_v3(uint_t kind, uint_t isroot, uint_t len) +{ + return (CTF_V3_TYPE_INFO(kind, isroot, len)); +} + +static int +type_isparent_v3(uint_t id) +{ + return (CTF_V3_TYPE_ISPARENT(id)); +} + +static int +type_ischild_v3(uint_t id) +{ + return (CTF_V3_TYPE_ISCHILD(id)); +} + +static uint_t +type_to_index_v3(uint_t t) +{ + return (CTF_V3_TYPE_TO_INDEX(t)); +} + +static uint_t +index_to_type_v3(uint_t id, uint_t child) +{ + return (CTF_V3_INDEX_TO_TYPE(id, child)); +} + +#define CTF_FILEOPS_ENTRY(v) \ + { \ + .ctfo_get_kind = get_kind_v ## v, \ + .ctfo_get_root = get_root_v ## v, \ + .ctfo_get_vlen = get_vlen_v ## v, \ + .ctfo_get_max_vlen = get_max_vlen_v ## v, \ + .ctfo_get_max_size = get_max_size_v ## v, \ + .ctfo_get_max_type = get_max_type_v ## v, \ + .ctfo_get_lsize_sent = get_lsize_sent_v ## v, \ + .ctfo_get_lstruct_thresh = get_lstruct_thresh_v ## v, \ + .ctfo_type_info = type_info_v ## v, \ + .ctfo_type_isparent = type_isparent_v ## v, \ + .ctfo_type_ischild = type_ischild_v ## v, \ + .ctfo_type_to_index = type_to_index_v ## v, \ + .ctfo_index_to_type = index_to_type_v ## v \ + } + static const ctf_fileops_t ctf_fileops[] = { { NULL, NULL }, { NULL, NULL }, - { get_kind_v2, get_root_v2, get_vlen_v2 }, + CTF_FILEOPS_ENTRY(2), + CTF_FILEOPS_ENTRY(3), }; /* * Convert a 32-bit ELF symbol into GElf (Elf64) and return a pointer to it. */ static Elf64_Sym * sym_to_gelf(const Elf32_Sym *src, Elf64_Sym *dst) { dst->st_name = src->st_name; dst->st_value = src->st_value; dst->st_size = src->st_size; dst->st_info = src->st_info; dst->st_other = src->st_other; dst->st_shndx = src->st_shndx; return (dst); } /* * Initialize the symtab translation table by filling each entry with the * offset of the CTF type or function data corresponding to each STT_FUNC or * STT_OBJECT entry in the symbol table. */ static int init_symtab(ctf_file_t *fp, const ctf_header_t *hp, const ctf_sect_t *sp, const ctf_sect_t *strp) { const uchar_t *symp = sp->cts_data; uint_t *xp = fp->ctf_sxlate; uint_t *xend = xp + fp->ctf_nsyms; uint_t objtoff = hp->cth_objtoff; uint_t funcoff = hp->cth_funcoff; - ushort_t info, vlen; + uint_t info, vlen; + Elf64_Sym sym, *gsp; const char *name; /* * The CTF data object and function type sections are ordered to match * the relative order of the respective symbol types in the symtab. * If no type information is available for a symbol table entry, a * pad is inserted in the CTF section. As a further optimization, * anonymous or undefined symbols are omitted from the CTF data. */ for (; xp < xend; xp++, symp += sp->cts_entsize) { if (sp->cts_entsize == sizeof (Elf32_Sym)) gsp = sym_to_gelf((Elf32_Sym *)(uintptr_t)symp, &sym); else gsp = (Elf64_Sym *)(uintptr_t)symp; if (gsp->st_name < strp->cts_size) name = (const char *)strp->cts_data + gsp->st_name; else name = _CTF_NULLSTR; if (gsp->st_name == 0 || gsp->st_shndx == SHN_UNDEF || strcmp(name, "_START_") == 0 || strcmp(name, "_END_") == 0) { *xp = -1u; continue; } switch (ELF64_ST_TYPE(gsp->st_info)) { case STT_OBJECT: if (objtoff >= hp->cth_funcoff || (gsp->st_shndx == SHN_ABS && gsp->st_value == 0)) { *xp = -1u; break; } *xp = objtoff; - objtoff += sizeof (ushort_t); + objtoff += fp->ctf_idwidth; break; case STT_FUNC: if (funcoff >= hp->cth_typeoff) { *xp = -1u; break; } *xp = funcoff; - info = *(ushort_t *)((uintptr_t)fp->ctf_buf + funcoff); + info = *(uint_t *)((uintptr_t)fp->ctf_buf + funcoff); vlen = LCTF_INFO_VLEN(fp, info); /* * If we encounter a zero pad at the end, just skip it. * Otherwise skip over the function and its return type * (+2) and the argument list (vlen). */ if (LCTF_INFO_KIND(fp, info) == CTF_K_UNKNOWN && vlen == 0) - funcoff += sizeof (ushort_t); /* skip pad */ + funcoff += fp->ctf_idwidth; else - funcoff += sizeof (ushort_t) * (vlen + 2); + funcoff += + roundup2(fp->ctf_idwidth * (vlen + 2), 4); break; default: *xp = -1u; break; } } ctf_dprintf("loaded %lu symtab entries\n", fp->ctf_nsyms); return (0); } /* * Initialize the type ID translation table with the byte offset of each type, * and initialize the hash tables of each named type. */ static int init_types(ctf_file_t *fp, const ctf_header_t *cth) { - /* LINTED - pointer alignment */ - const ctf_type_t *tbuf = (ctf_type_t *)(fp->ctf_buf + cth->cth_typeoff); - /* LINTED - pointer alignment */ - const ctf_type_t *tend = (ctf_type_t *)(fp->ctf_buf + cth->cth_stroff); + const void *tbuf = (const void *)(fp->ctf_buf + cth->cth_typeoff); + const void *tend = (const void *)(fp->ctf_buf + cth->cth_stroff); ulong_t pop[CTF_K_MAX + 1] = { 0 }; - const ctf_type_t *tp; + const void *tp; ctf_hash_t *hp; - ushort_t id, dst; + uint_t id, dst; uint_t *xp; /* * We initially determine whether the container is a child or a parent * based on the value of cth_parname. To support containers that pre- * date cth_parname, we also scan the types themselves for references * to values in the range reserved for child types in our first pass. */ int child = cth->cth_parname != 0; int nlstructs = 0, nlunions = 0; int err; /* * We make two passes through the entire type section. In this first * pass, we count the number of each type and the total number of types. */ for (tp = tbuf; tp < tend; fp->ctf_typemax++) { - ushort_t kind = LCTF_INFO_KIND(fp, tp->ctt_info); - ulong_t vlen = LCTF_INFO_VLEN(fp, tp->ctt_info); ssize_t size, increment; size_t vbytes; - uint_t n; + uint_t kind, n, type, vlen; (void) ctf_get_ctt_size(fp, tp, &size, &increment); + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); + ctf_get_ctt_index(fp, tp, NULL, &type, NULL); switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: vbytes = sizeof (uint_t); break; case CTF_K_ARRAY: - vbytes = sizeof (ctf_array_t); + if (fp->ctf_version == CTF_VERSION_2) + vbytes = sizeof (struct ctf_array_v2); + else + vbytes = sizeof (struct ctf_array_v3); break; case CTF_K_FUNCTION: - vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); + vbytes = roundup2(fp->ctf_idwidth * vlen, 4); break; case CTF_K_STRUCT: - case CTF_K_UNION: - if (size < CTF_LSTRUCT_THRESH) { - ctf_member_t *mp = (ctf_member_t *) - ((uintptr_t)tp + increment); - - vbytes = sizeof (ctf_member_t) * vlen; - for (n = vlen; n != 0; n--, mp++) - child |= CTF_TYPE_ISCHILD(mp->ctm_type); - } else { - ctf_lmember_t *lmp = (ctf_lmember_t *) - ((uintptr_t)tp + increment); + case CTF_K_UNION: { + size_t increment1; + uint_t type; + const void *mp = + (const void *)((uintptr_t)tp + increment); - vbytes = sizeof (ctf_lmember_t) * vlen; - for (n = vlen; n != 0; n--, lmp++) - child |= - CTF_TYPE_ISCHILD(lmp->ctlm_type); + vbytes = 0; + for (n = vlen; n != 0; n--, mp += increment1) { + ctf_get_ctm_info(fp, mp, size, &increment1, &type, + NULL, NULL); + child |= LCTF_TYPE_ISCHILD(fp, type); + vbytes += increment1; } break; + } case CTF_K_ENUM: vbytes = sizeof (ctf_enum_t) * vlen; break; case CTF_K_FORWARD: /* * For forward declarations, ctt_type is the CTF_K_* * kind for the tag, so bump that population count too. * If ctt_type is unknown, treat the tag as a struct. */ - if (tp->ctt_type == CTF_K_UNKNOWN || - tp->ctt_type >= CTF_K_MAX) + if (type == CTF_K_UNKNOWN || type >= CTF_K_MAX) pop[CTF_K_STRUCT]++; else - pop[tp->ctt_type]++; + pop[type]++; /*FALLTHRU*/ case CTF_K_UNKNOWN: vbytes = 0; break; case CTF_K_POINTER: case CTF_K_TYPEDEF: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: - child |= CTF_TYPE_ISCHILD(tp->ctt_type); + child |= LCTF_TYPE_ISCHILD(fp, type); vbytes = 0; break; default: ctf_dprintf("detected invalid CTF kind -- %u\n", kind); return (ECTF_CORRUPT); } - tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); + tp = (const void *)((uintptr_t)tp + increment + vbytes); pop[kind]++; } /* * If we detected a reference to a child type ID, then we know this * container is a child and may have a parent's types imported later. */ if (child) { ctf_dprintf("CTF container %p is a child\n", (void *)fp); fp->ctf_flags |= LCTF_CHILD; } else ctf_dprintf("CTF container %p is a parent\n", (void *)fp); /* * Now that we've counted up the number of each type, we can allocate * the hash tables, type translation table, and pointer table. */ if ((err = ctf_hash_create(&fp->ctf_structs, pop[CTF_K_STRUCT])) != 0) return (err); if ((err = ctf_hash_create(&fp->ctf_unions, pop[CTF_K_UNION])) != 0) return (err); if ((err = ctf_hash_create(&fp->ctf_enums, pop[CTF_K_ENUM])) != 0) return (err); if ((err = ctf_hash_create(&fp->ctf_names, pop[CTF_K_INTEGER] + pop[CTF_K_FLOAT] + pop[CTF_K_FUNCTION] + pop[CTF_K_TYPEDEF] + pop[CTF_K_POINTER] + pop[CTF_K_VOLATILE] + pop[CTF_K_CONST] + pop[CTF_K_RESTRICT])) != 0) return (err); fp->ctf_txlate = ctf_alloc(sizeof (uint_t) * (fp->ctf_typemax + 1)); - fp->ctf_ptrtab = ctf_alloc(sizeof (ushort_t) * (fp->ctf_typemax + 1)); + fp->ctf_ptrtab = ctf_alloc(sizeof (uint_t) * (fp->ctf_typemax + 1)); if (fp->ctf_txlate == NULL || fp->ctf_ptrtab == NULL) return (EAGAIN); /* memory allocation failed */ xp = fp->ctf_txlate; *xp++ = 0; /* type id 0 is used as a sentinel value */ bzero(fp->ctf_txlate, sizeof (uint_t) * (fp->ctf_typemax + 1)); - bzero(fp->ctf_ptrtab, sizeof (ushort_t) * (fp->ctf_typemax + 1)); + bzero(fp->ctf_ptrtab, sizeof (uint_t) * (fp->ctf_typemax + 1)); /* * In the second pass through the types, we fill in each entry of the * type and pointer tables and add names to the appropriate hashes. */ for (id = 1, tp = tbuf; tp < tend; xp++, id++) { - ushort_t kind = LCTF_INFO_KIND(fp, tp->ctt_info); - ulong_t vlen = LCTF_INFO_VLEN(fp, tp->ctt_info); + const struct ctf_type_v3 *ctt = tp; + uint_t kind, type, vlen; ssize_t size, increment; const char *name; size_t vbytes; ctf_helem_t *hep; ctf_encoding_t cte; (void) ctf_get_ctt_size(fp, tp, &size, &increment); - name = ctf_strptr(fp, tp->ctt_name); + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); + ctf_get_ctt_index(fp, tp, NULL, &type, NULL); + name = ctf_type_rname(fp, tp); switch (kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: /* * Only insert a new integer base type definition if * this type name has not been defined yet. We re-use * the names with different encodings for bit-fields. */ if ((hep = ctf_hash_lookup(&fp->ctf_names, fp, name, strlen(name))) == NULL) { err = ctf_hash_insert(&fp->ctf_names, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), + ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); } else if (ctf_type_encoding(fp, hep->h_type, &cte) == 0 && cte.cte_bits == 0) { /* * Work-around SOS8 stabs bug: replace existing * intrinsic w/ same name if it was zero bits. */ - hep->h_type = CTF_INDEX_TO_TYPE(id, child); + hep->h_type = LCTF_INDEX_TO_TYPE(fp, id, child); } vbytes = sizeof (uint_t); break; case CTF_K_ARRAY: - vbytes = sizeof (ctf_array_t); + if (fp->ctf_version == CTF_VERSION_2) + vbytes = sizeof (struct ctf_array_v2); + else + vbytes = sizeof (struct ctf_array_v3); break; case CTF_K_FUNCTION: err = ctf_hash_insert(&fp->ctf_names, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); - vbytes = sizeof (ushort_t) * (vlen + (vlen & 1)); + vbytes = roundup2(fp->ctf_idwidth * vlen, 4); break; case CTF_K_STRUCT: err = ctf_hash_define(&fp->ctf_structs, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); - if (size < CTF_LSTRUCT_THRESH) - vbytes = sizeof (ctf_member_t) * vlen; - else { - vbytes = sizeof (ctf_lmember_t) * vlen; - nlstructs++; + if (fp->ctf_version == CTF_VERSION_2) { + if (size < LCTF_LSTRUCT_THRESH(fp)) + vbytes = sizeof (struct ctf_member_v2) * + vlen; + else { + vbytes = + sizeof (struct ctf_lmember_v2) * + vlen; + nlstructs++; + } + } else { + if (size < LCTF_LSTRUCT_THRESH(fp)) + vbytes = sizeof (struct ctf_member_v3) * + vlen; + else { + vbytes = + sizeof (struct ctf_lmember_v3) * + vlen; + nlstructs++; + } } break; case CTF_K_UNION: err = ctf_hash_define(&fp->ctf_unions, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); - if (size < CTF_LSTRUCT_THRESH) - vbytes = sizeof (ctf_member_t) * vlen; - else { - vbytes = sizeof (ctf_lmember_t) * vlen; - nlunions++; + if (fp->ctf_version == CTF_VERSION_2) { + if (size < LCTF_LSTRUCT_THRESH(fp)) + vbytes = sizeof (struct ctf_member_v2) * + vlen; + else { + vbytes = + sizeof (struct ctf_lmember_v2) * + vlen; + nlunions++; + } + } else { + if (size < LCTF_LSTRUCT_THRESH(fp)) + vbytes = sizeof (struct ctf_member_v3) * + vlen; + else { + vbytes = + sizeof (struct ctf_lmember_v3) * + vlen; + nlunions++; + } } break; case CTF_K_ENUM: err = ctf_hash_define(&fp->ctf_enums, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); vbytes = sizeof (ctf_enum_t) * vlen; break; case CTF_K_TYPEDEF: err = ctf_hash_insert(&fp->ctf_names, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); vbytes = 0; break; case CTF_K_FORWARD: /* * Only insert forward tags into the given hash if the * type or tag name is not already present. */ - switch (tp->ctt_type) { + switch (type) { case CTF_K_STRUCT: hp = &fp->ctf_structs; break; case CTF_K_UNION: hp = &fp->ctf_unions; break; case CTF_K_ENUM: hp = &fp->ctf_enums; break; default: hp = &fp->ctf_structs; } if (ctf_hash_lookup(hp, fp, name, strlen(name)) == NULL) { err = ctf_hash_insert(hp, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), + ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); } vbytes = 0; break; case CTF_K_POINTER: /* * If the type referenced by the pointer is in this CTF * container, then store the index of the pointer type * in fp->ctf_ptrtab[ index of referenced type ]. */ - if (CTF_TYPE_ISCHILD(tp->ctt_type) == child && - CTF_TYPE_TO_INDEX(tp->ctt_type) <= fp->ctf_typemax) + if (LCTF_TYPE_ISCHILD(fp, type) == child && + LCTF_TYPE_TO_INDEX(fp, type) <= fp->ctf_typemax) fp->ctf_ptrtab[ - CTF_TYPE_TO_INDEX(tp->ctt_type)] = id; + LCTF_TYPE_TO_INDEX(fp, type)] = id; /*FALLTHRU*/ case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: err = ctf_hash_insert(&fp->ctf_names, fp, - CTF_INDEX_TO_TYPE(id, child), tp->ctt_name); + LCTF_INDEX_TO_TYPE(fp, id, child), ctt->ctt_name); if (err != 0 && err != ECTF_STRTAB) return (err); /*FALLTHRU*/ default: vbytes = 0; break; } *xp = (uint_t)((uintptr_t)tp - (uintptr_t)fp->ctf_buf); - tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes); + tp = (const void *)((uintptr_t)tp + increment + vbytes); } ctf_dprintf("%lu total types processed\n", fp->ctf_typemax); ctf_dprintf("%u enum names hashed\n", ctf_hash_size(&fp->ctf_enums)); ctf_dprintf("%u struct names hashed (%d long)\n", ctf_hash_size(&fp->ctf_structs), nlstructs); ctf_dprintf("%u union names hashed (%d long)\n", ctf_hash_size(&fp->ctf_unions), nlunions); ctf_dprintf("%u base type names hashed\n", ctf_hash_size(&fp->ctf_names)); /* * Make an additional pass through the pointer table to find pointers * that point to anonymous typedef nodes. If we find one, modify the * pointer table so that the pointer is also known to point to the * node that is referenced by the anonymous typedef node. */ for (id = 1; id <= fp->ctf_typemax; id++) { if ((dst = fp->ctf_ptrtab[id]) != 0) { + uint_t index, kind; + int ischild; + tp = LCTF_INDEX_TO_TYPEPTR(fp, id); + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + ctf_get_ctt_index(fp, tp, &index, NULL, &ischild); - if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_TYPEDEF && - strcmp(ctf_strptr(fp, tp->ctt_name), "") == 0 && - CTF_TYPE_ISCHILD(tp->ctt_type) == child && - CTF_TYPE_TO_INDEX(tp->ctt_type) <= fp->ctf_typemax) - fp->ctf_ptrtab[ - CTF_TYPE_TO_INDEX(tp->ctt_type)] = dst; + if (kind == CTF_K_TYPEDEF && + strcmp(ctf_type_rname(fp, tp), "") == 0 && + ischild == child && index <= fp->ctf_typemax) + fp->ctf_ptrtab[index] = dst; } } return (0); } /* * Decode the specified CTF buffer and optional symbol table and create a new * CTF container representing the symbolic debugging information. This code * can be used directly by the debugger, or it can be used as the engine for * ctf_fdopen() or ctf_open(), below. */ ctf_file_t * ctf_bufopen(const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, const ctf_sect_t *strsect, int *errp) { const ctf_preamble_t *pp; ctf_header_t hp; ctf_file_t *fp; void *buf, *base; size_t size, hdrsz; int err; if (ctfsect == NULL || ((symsect == NULL) != (strsect == NULL))) return (ctf_set_open_errno(errp, EINVAL)); if (symsect != NULL && symsect->cts_entsize != sizeof (Elf32_Sym) && symsect->cts_entsize != sizeof (Elf64_Sym)) return (ctf_set_open_errno(errp, ECTF_SYMTAB)); if (symsect != NULL && symsect->cts_data == NULL) return (ctf_set_open_errno(errp, ECTF_SYMBAD)); if (strsect != NULL && strsect->cts_data == NULL) return (ctf_set_open_errno(errp, ECTF_STRBAD)); if (ctfsect->cts_size < sizeof (ctf_preamble_t)) return (ctf_set_open_errno(errp, ECTF_NOCTFBUF)); pp = (const ctf_preamble_t *)ctfsect->cts_data; ctf_dprintf("ctf_bufopen: magic=0x%x version=%u\n", pp->ctp_magic, pp->ctp_version); /* * Validate each part of the CTF header (either V1 or V2). * First, we validate the preamble (common to all versions). At that * point, we know specific header version, and can validate the * version-specific parts including section offsets and alignments. */ if (pp->ctp_magic != CTF_MAGIC) return (ctf_set_open_errno(errp, ECTF_NOCTFBUF)); - if (pp->ctp_version == CTF_VERSION_2) { + if (pp->ctp_version == CTF_VERSION_2 || + pp->ctp_version == CTF_VERSION_3) { if (ctfsect->cts_size < sizeof (ctf_header_t)) return (ctf_set_open_errno(errp, ECTF_NOCTFBUF)); bcopy(ctfsect->cts_data, &hp, sizeof (hp)); hdrsz = sizeof (ctf_header_t); } else return (ctf_set_open_errno(errp, ECTF_CTFVERS)); size = hp.cth_stroff + hp.cth_strlen; ctf_dprintf("ctf_bufopen: uncompressed size=%lu\n", (ulong_t)size); if (hp.cth_lbloff > size || hp.cth_objtoff > size || hp.cth_funcoff > size || hp.cth_typeoff > size || hp.cth_stroff > size) return (ctf_set_open_errno(errp, ECTF_CORRUPT)); if (hp.cth_lbloff > hp.cth_objtoff || hp.cth_objtoff > hp.cth_funcoff || hp.cth_funcoff > hp.cth_typeoff || hp.cth_typeoff > hp.cth_stroff) return (ctf_set_open_errno(errp, ECTF_CORRUPT)); if ((hp.cth_lbloff & 3) || (hp.cth_objtoff & 1) || (hp.cth_funcoff & 1) || (hp.cth_typeoff & 3)) return (ctf_set_open_errno(errp, ECTF_CORRUPT)); /* * Once everything is determined to be valid, attempt to decompress * the CTF data buffer if it is compressed. Otherwise we just put * the data section's buffer pointer into ctf_buf, below. */ if (hp.cth_flags & CTF_F_COMPRESS) { size_t srclen, dstlen; const void *src; int rc = Z_OK; if (ctf_zopen(errp) == NULL) return (NULL); /* errp is set for us */ if ((base = ctf_data_alloc(size + hdrsz)) == MAP_FAILED) return (ctf_set_open_errno(errp, ECTF_ZALLOC)); bcopy(ctfsect->cts_data, base, hdrsz); ((ctf_preamble_t *)base)->ctp_flags &= ~CTF_F_COMPRESS; buf = (uchar_t *)base + hdrsz; src = (uchar_t *)ctfsect->cts_data + hdrsz; srclen = ctfsect->cts_size - hdrsz; dstlen = size; if ((rc = z_uncompress(buf, &dstlen, src, srclen)) != Z_OK) { ctf_dprintf("zlib inflate err: %s\n", z_strerror(rc)); ctf_data_free(base, size + hdrsz); return (ctf_set_open_errno(errp, ECTF_DECOMPRESS)); } if (dstlen != size) { ctf_dprintf("zlib inflate short -- got %lu of %lu " "bytes\n", (ulong_t)dstlen, (ulong_t)size); ctf_data_free(base, size + hdrsz); return (ctf_set_open_errno(errp, ECTF_CORRUPT)); } ctf_data_protect(base, size + hdrsz); } else { base = (void *)ctfsect->cts_data; buf = (uchar_t *)base + hdrsz; } /* * Once we have uncompressed and validated the CTF data buffer, we can * proceed with allocating a ctf_file_t and initializing it. */ if ((fp = ctf_alloc(sizeof (ctf_file_t))) == NULL) return (ctf_set_open_errno(errp, EAGAIN)); bzero(fp, sizeof (ctf_file_t)); fp->ctf_version = hp.cth_version; + fp->ctf_idwidth = fp->ctf_version == CTF_VERSION_2 ? 2 : 4; fp->ctf_fileops = &ctf_fileops[hp.cth_version]; bcopy(ctfsect, &fp->ctf_data, sizeof (ctf_sect_t)); if (symsect != NULL) { bcopy(symsect, &fp->ctf_symtab, sizeof (ctf_sect_t)); bcopy(strsect, &fp->ctf_strtab, sizeof (ctf_sect_t)); } if (fp->ctf_data.cts_name != NULL) fp->ctf_data.cts_name = ctf_strdup(fp->ctf_data.cts_name); if (fp->ctf_symtab.cts_name != NULL) fp->ctf_symtab.cts_name = ctf_strdup(fp->ctf_symtab.cts_name); if (fp->ctf_strtab.cts_name != NULL) fp->ctf_strtab.cts_name = ctf_strdup(fp->ctf_strtab.cts_name); if (fp->ctf_data.cts_name == NULL) fp->ctf_data.cts_name = _CTF_NULLSTR; if (fp->ctf_symtab.cts_name == NULL) fp->ctf_symtab.cts_name = _CTF_NULLSTR; if (fp->ctf_strtab.cts_name == NULL) fp->ctf_strtab.cts_name = _CTF_NULLSTR; fp->ctf_str[CTF_STRTAB_0].cts_strs = (const char *)buf + hp.cth_stroff; fp->ctf_str[CTF_STRTAB_0].cts_len = hp.cth_strlen; if (strsect != NULL) { fp->ctf_str[CTF_STRTAB_1].cts_strs = strsect->cts_data; fp->ctf_str[CTF_STRTAB_1].cts_len = strsect->cts_size; } fp->ctf_base = base; fp->ctf_buf = buf; fp->ctf_size = size + hdrsz; /* * If we have a parent container name and label, store the relocated * string pointers in the CTF container for easy access later. */ if (hp.cth_parlabel != 0) fp->ctf_parlabel = ctf_strptr(fp, hp.cth_parlabel); if (hp.cth_parname != 0) fp->ctf_parname = ctf_strptr(fp, hp.cth_parname); ctf_dprintf("ctf_bufopen: parent name %s (label %s)\n", fp->ctf_parname ? fp->ctf_parname : "", fp->ctf_parlabel ? fp->ctf_parlabel : ""); /* * If we have a symbol table section, allocate and initialize * the symtab translation table, pointed to by ctf_sxlate. */ if (symsect != NULL) { fp->ctf_nsyms = symsect->cts_size / symsect->cts_entsize; fp->ctf_sxlate = ctf_alloc(fp->ctf_nsyms * sizeof (uint_t)); if (fp->ctf_sxlate == NULL) { (void) ctf_set_open_errno(errp, EAGAIN); goto bad; } if ((err = init_symtab(fp, &hp, symsect, strsect)) != 0) { (void) ctf_set_open_errno(errp, err); goto bad; } } if ((err = init_types(fp, &hp)) != 0) { (void) ctf_set_open_errno(errp, err); goto bad; } /* * Initialize the ctf_lookup_by_name top-level dictionary. We keep an * array of type name prefixes and the corresponding ctf_hash to use. * NOTE: This code must be kept in sync with the code in ctf_update(). */ fp->ctf_lookups[0].ctl_prefix = "struct"; fp->ctf_lookups[0].ctl_len = strlen(fp->ctf_lookups[0].ctl_prefix); fp->ctf_lookups[0].ctl_hash = &fp->ctf_structs; fp->ctf_lookups[1].ctl_prefix = "union"; fp->ctf_lookups[1].ctl_len = strlen(fp->ctf_lookups[1].ctl_prefix); fp->ctf_lookups[1].ctl_hash = &fp->ctf_unions; fp->ctf_lookups[2].ctl_prefix = "enum"; fp->ctf_lookups[2].ctl_len = strlen(fp->ctf_lookups[2].ctl_prefix); fp->ctf_lookups[2].ctl_hash = &fp->ctf_enums; fp->ctf_lookups[3].ctl_prefix = _CTF_NULLSTR; fp->ctf_lookups[3].ctl_len = strlen(fp->ctf_lookups[3].ctl_prefix); fp->ctf_lookups[3].ctl_hash = &fp->ctf_names; fp->ctf_lookups[4].ctl_prefix = NULL; fp->ctf_lookups[4].ctl_len = 0; fp->ctf_lookups[4].ctl_hash = NULL; if (symsect != NULL) { if (symsect->cts_entsize == sizeof (Elf64_Sym)) (void) ctf_setmodel(fp, CTF_MODEL_LP64); else (void) ctf_setmodel(fp, CTF_MODEL_ILP32); } else (void) ctf_setmodel(fp, CTF_MODEL_NATIVE); fp->ctf_refcnt = 1; return (fp); bad: ctf_close(fp); return (NULL); } /* * Dupliate a ctf_file_t and its underlying section information into a new * container. This works by copying the three ctf_sect_t's of the original * container if they exist and passing those into ctf_bufopen. To copy those, we * mmap anonymous memory with ctf_data_alloc and bcopy the data across. It's not * the cheapest thing, but it's what we've got. */ ctf_file_t * ctf_dup(ctf_file_t *ofp) { ctf_file_t *fp; ctf_sect_t ctfsect, symsect, strsect; ctf_sect_t *ctp, *symp, *strp; void *cbuf, *symbuf, *strbuf; int err; cbuf = symbuf = strbuf = NULL; /* * The ctfsect isn't allowed to not exist, but the symbol and string * section might not. We only need to copy the data of the section, not * the name, as ctf_bufopen will take care of that. */ bcopy(&ofp->ctf_data, &ctfsect, sizeof (ctf_sect_t)); cbuf = ctf_data_alloc(ctfsect.cts_size); if (cbuf == NULL) { (void) ctf_set_errno(ofp, ECTF_MMAP); return (NULL); } bcopy(ctfsect.cts_data, cbuf, ctfsect.cts_size); ctf_data_protect(cbuf, ctfsect.cts_size); ctfsect.cts_data = cbuf; ctfsect.cts_offset = 0; ctp = &ctfsect; if (ofp->ctf_symtab.cts_data != NULL) { bcopy(&ofp->ctf_symtab, &symsect, sizeof (ctf_sect_t)); symbuf = ctf_data_alloc(symsect.cts_size); if (symbuf == NULL) { (void) ctf_set_errno(ofp, ECTF_MMAP); goto err; } bcopy(symsect.cts_data, symbuf, symsect.cts_size); ctf_data_protect(symbuf, symsect.cts_size); symsect.cts_data = symbuf; symsect.cts_offset = 0; symp = &symsect; } else { symp = NULL; } if (ofp->ctf_strtab.cts_data != NULL) { bcopy(&ofp->ctf_strtab, &strsect, sizeof (ctf_sect_t)); strbuf = ctf_data_alloc(strsect.cts_size); if (strbuf == NULL) { (void) ctf_set_errno(ofp, ECTF_MMAP); goto err; } bcopy(strsect.cts_data, strbuf, strsect.cts_size); ctf_data_protect(strbuf, strsect.cts_size); strsect.cts_data = strbuf; strsect.cts_offset = 0; strp = &strsect; } else { strp = NULL; } fp = ctf_bufopen(ctp, symp, strp, &err); if (fp == NULL) { (void) ctf_set_errno(ofp, err); goto err; } fp->ctf_flags |= LCTF_MMAP; return (fp); err: ctf_data_free(cbuf, ctfsect.cts_size); if (symbuf != NULL) ctf_data_free(symbuf, symsect.cts_size); if (strbuf != NULL) ctf_data_free(strbuf, strsect.cts_size); return (NULL); } /* * Close the specified CTF container and free associated data structures. Note * that ctf_close() is a reference counted operation: if the specified file is * the parent of other active containers, its reference count will be greater * than one and it will be freed later when no active children exist. */ void ctf_close(ctf_file_t *fp) { ctf_dtdef_t *dtd, *ntd; if (fp == NULL) return; /* allow ctf_close(NULL) to simplify caller code */ ctf_dprintf("ctf_close(%p) refcnt=%u\n", (void *)fp, fp->ctf_refcnt); if (fp->ctf_refcnt > 1) { fp->ctf_refcnt--; return; } if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); /* * Note, to work properly with reference counting on the dynamic * section, we must delete the list in reverse. */ for (dtd = ctf_list_prev(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) { ntd = ctf_list_prev(dtd); ctf_dtd_delete(fp, dtd); } ctf_free(fp->ctf_dthash, fp->ctf_dthashlen * sizeof (ctf_dtdef_t *)); if (fp->ctf_flags & LCTF_MMAP) { if (fp->ctf_data.cts_data != NULL) ctf_sect_munmap(&fp->ctf_data); if (fp->ctf_symtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_symtab); if (fp->ctf_strtab.cts_data != NULL) ctf_sect_munmap(&fp->ctf_strtab); } if (fp->ctf_data.cts_name != _CTF_NULLSTR && fp->ctf_data.cts_name != NULL) { ctf_free((char *)fp->ctf_data.cts_name, strlen(fp->ctf_data.cts_name) + 1); } if (fp->ctf_symtab.cts_name != _CTF_NULLSTR && fp->ctf_symtab.cts_name != NULL) { ctf_free((char *)fp->ctf_symtab.cts_name, strlen(fp->ctf_symtab.cts_name) + 1); } if (fp->ctf_strtab.cts_name != _CTF_NULLSTR && fp->ctf_strtab.cts_name != NULL) { ctf_free((char *)fp->ctf_strtab.cts_name, strlen(fp->ctf_strtab.cts_name) + 1); } if (fp->ctf_base != fp->ctf_data.cts_data && fp->ctf_base != NULL) ctf_data_free((void *)fp->ctf_base, fp->ctf_size); if (fp->ctf_sxlate != NULL) ctf_free(fp->ctf_sxlate, sizeof (uint_t) * fp->ctf_nsyms); if (fp->ctf_txlate != NULL) { ctf_free(fp->ctf_txlate, sizeof (uint_t) * (fp->ctf_typemax + 1)); } if (fp->ctf_ptrtab != NULL) { ctf_free(fp->ctf_ptrtab, - sizeof (ushort_t) * (fp->ctf_typemax + 1)); + sizeof (uint_t) * (fp->ctf_typemax + 1)); } ctf_hash_destroy(&fp->ctf_structs); ctf_hash_destroy(&fp->ctf_unions); ctf_hash_destroy(&fp->ctf_enums); ctf_hash_destroy(&fp->ctf_names); ctf_free(fp, sizeof (ctf_file_t)); } /* * Return the CTF handle for the parent CTF container, if one exists. * Otherwise return NULL to indicate this container has no imported parent. */ ctf_file_t * ctf_parent_file(ctf_file_t *fp) { return (fp->ctf_parent); } /* * Return the name of the parent CTF container, if one exists. Otherwise * return NULL to indicate this container is a root container. */ const char * ctf_parent_name(ctf_file_t *fp) { return (fp->ctf_parname); } /* * Import the types from the specified parent container by storing a pointer * to it in ctf_parent and incrementing its reference count. Only one parent * is allowed: if a parent already exists, it is replaced by the new parent. */ int ctf_import(ctf_file_t *fp, ctf_file_t *pfp) { if (fp == NULL || fp == pfp || (pfp != NULL && pfp->ctf_refcnt == 0)) return (ctf_set_errno(fp, EINVAL)); if (pfp != NULL && pfp->ctf_dmodel != fp->ctf_dmodel) return (ctf_set_errno(fp, ECTF_DMODEL)); if (fp->ctf_parent != NULL) ctf_close(fp->ctf_parent); if (pfp != NULL) { fp->ctf_flags |= LCTF_CHILD; pfp->ctf_refcnt++; } fp->ctf_parent = pfp; return (0); } /* * Set the data model constant for the CTF container. */ int ctf_setmodel(ctf_file_t *fp, int model) { const ctf_dmodel_t *dp; for (dp = _libctf_models; dp->ctd_name != NULL; dp++) { if (dp->ctd_code == model) { fp->ctf_dmodel = dp; return (0); } } return (ctf_set_errno(fp, EINVAL)); } /* * Return the data model constant for the CTF container. */ int ctf_getmodel(ctf_file_t *fp) { return (fp->ctf_dmodel->ctd_code); } void ctf_setspecific(ctf_file_t *fp, void *data) { fp->ctf_specific = data; } void * ctf_getspecific(ctf_file_t *fp) { return (fp->ctf_specific); } diff --git a/cddl/contrib/opensolaris/common/ctf/ctf_types.c b/cddl/contrib/opensolaris/common/ctf/ctf_types.c index 5b6b07655d82..de8269659c29 100644 --- a/cddl/contrib/opensolaris/common/ctf/ctf_types.c +++ b/cddl/contrib/opensolaris/common/ctf/ctf_types.c @@ -1,885 +1,1022 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include +void +ctf_get_ctt_index(const ctf_file_t *fp, const void *v, uint_t *indexp, + uint_t *typep, int *ischildp) +{ + uint_t index, type; + int ischild; + + if (fp->ctf_version == CTF_VERSION_2) { + const struct ctf_type_v2 *ctt = v; + + type = ctt->ctt_type; + index = CTF_V2_TYPE_TO_INDEX(ctt->ctt_type); + ischild = CTF_V2_TYPE_ISCHILD(ctt->ctt_type); + } else { + const struct ctf_type_v3 *ctt = v; + + type = ctt->ctt_type; + index = CTF_V3_TYPE_TO_INDEX(ctt->ctt_type); + ischild = CTF_V3_TYPE_ISCHILD(ctt->ctt_type); + } + + if (indexp != NULL) + *indexp = index; + if (typep != NULL) + *typep = type; + if (ischildp != NULL) + *ischildp = ischild; +} + +void +ctf_get_ctt_info(const ctf_file_t *fp, const void *v, uint_t *kindp, + uint_t *vlenp, int *isrootp) +{ + uint_t kind, vlen; + int isroot; + + if (fp->ctf_version == CTF_VERSION_2) { + const struct ctf_type_v2 *ctt = v; + + kind = CTF_V2_INFO_KIND(ctt->ctt_info); + vlen = CTF_V2_INFO_VLEN(ctt->ctt_info); + isroot = CTF_V2_INFO_ISROOT(ctt->ctt_info); + } else { + const struct ctf_type_v3 *ctt = v; + + kind = CTF_V3_INFO_KIND(ctt->ctt_info); + vlen = CTF_V3_INFO_VLEN(ctt->ctt_info); + isroot = CTF_V3_INFO_ISROOT(ctt->ctt_info); + } + + if (kindp != NULL) + *kindp = kind; + if (vlenp != NULL) + *vlenp = vlen; + if (isrootp != NULL) + *isrootp = isroot; +} + ssize_t -ctf_get_ctt_size(const ctf_file_t *fp, const ctf_type_t *tp, ssize_t *sizep, +ctf_get_ctt_size(const ctf_file_t *fp, const void *v, ssize_t *sizep, ssize_t *incrementp) { ssize_t size, increment; - if (tp->ctt_size == CTF_LSIZE_SENT) { - size = CTF_TYPE_LSIZE(tp); - increment = sizeof (ctf_type_t); + if (fp->ctf_version == CTF_VERSION_2) { + const struct ctf_type_v2 *ctt = v; + + if (ctt->ctt_size == CTF_V2_LSIZE_SENT) { + size = (size_t)CTF_TYPE_LSIZE(ctt); + increment = sizeof (struct ctf_type_v2); + } else { + size = ctt->ctt_size; + increment = sizeof (struct ctf_stype_v2); + } } else { - size = tp->ctt_size; - increment = sizeof (ctf_stype_t); + const struct ctf_type_v3 *ctt = v; + + if (ctt->ctt_size == CTF_V3_LSIZE_SENT) { + size = (size_t)CTF_TYPE_LSIZE(ctt); + increment = sizeof (struct ctf_type_v3); + } else { + size = ctt->ctt_size; + increment = sizeof (struct ctf_stype_v3); + } } if (sizep) *sizep = size; if (incrementp) *incrementp = increment; return (size); } +/* + * Fetch info for a struct or union member. + */ +void +ctf_get_ctm_info(const ctf_file_t *fp, const void *v, size_t size, + size_t *incrementp, uint_t *typep, ulong_t *offsetp, const char **namep) +{ + size_t increment; + ulong_t offset; + uint_t name, type; + + if (fp->ctf_version == CTF_VERSION_2) { + if (size < CTF_V2_LSTRUCT_THRESH) { + const struct ctf_member_v2 *ctm = v; + + name = ctm->ctm_name; + type = ctm->ctm_type; + offset = ctm->ctm_offset; + increment = sizeof(*ctm); + } else { + const struct ctf_lmember_v2 *ctlm = v; + + name = ctlm->ctlm_name; + type = ctlm->ctlm_type; + offset = (ulong_t)CTF_LMEM_OFFSET(ctlm); + increment = sizeof(*ctlm); + } + } else { + if (size < CTF_V3_LSTRUCT_THRESH) { + const struct ctf_member_v3 *ctm = v; + + name = ctm->ctm_name; + type = ctm->ctm_type; + offset = ctm->ctm_offset; + increment = sizeof(*ctm); + } else { + const struct ctf_lmember_v3 *ctlm = v; + + name = ctlm->ctlm_name; + type = ctlm->ctlm_type; + offset = (ulong_t)CTF_LMEM_OFFSET(ctlm); + increment = sizeof(*ctlm); + } + } + + if (incrementp != NULL) + *incrementp = increment; + if (typep != NULL) + *typep = type; + if (offsetp != NULL) + *offsetp = offset; + if (namep != NULL) + *namep = ctf_strraw(fp, name); +} + /* * Iterate over the members of a STRUCT or UNION. We pass the name, member * type, and offset of each member to the specified callback function. */ int ctf_member_iter(ctf_file_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; ssize_t size, increment; - uint_t kind, n; + uint_t kind, n, vlen; int rc; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ (void) ctf_get_ctt_size(fp, tp, &size, &increment); - kind = LCTF_INFO_KIND(fp, tp->ctt_info); + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno(ofp, ECTF_NOTSOU)); - if (size < CTF_LSTRUCT_THRESH) { - const ctf_member_t *mp = (const ctf_member_t *) - ((uintptr_t)tp + increment); + const char *mp = (const char *)((uintptr_t)tp + increment); - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { - const char *name = ctf_strptr(fp, mp->ctm_name); - if ((rc = func(name, mp->ctm_type, mp->ctm_offset, - arg)) != 0) - return (rc); - } + for (n = vlen; n != 0; n--, mp += increment) { + const char *name; + ulong_t offset; + uint_t type; - } else { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) - ((uintptr_t)tp + increment); - - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { - const char *name = ctf_strptr(fp, lmp->ctlm_name); - if ((rc = func(name, lmp->ctlm_type, - (ulong_t)CTF_LMEM_OFFSET(lmp), arg)) != 0) - return (rc); - } + ctf_get_ctm_info(fp, mp, size, &increment, &type, &offset, + &name); + if ((rc = func(name, type, offset, arg)) != 0) + return (rc); } return (0); } /* * Iterate over the members of an ENUM. We pass the string name and associated * integer value of each enum element to the specified callback function. */ int ctf_enum_iter(ctf_file_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; const ctf_enum_t *ep; ssize_t increment; - uint_t n; + uint_t kind, n, vlen; int rc; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ - if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); + if (kind != CTF_K_ENUM) return (ctf_set_errno(ofp, ECTF_NOTENUM)); (void) ctf_get_ctt_size(fp, tp, NULL, &increment); ep = (const ctf_enum_t *)((uintptr_t)tp + increment); - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { + for (n = vlen; n != 0; n--, ep++) { const char *name = ctf_strptr(fp, ep->cte_name); if ((rc = func(name, ep->cte_value, arg)) != 0) return (rc); } return (0); } /* * Iterate over every root (user-visible) type in the given CTF container. * We pass the type ID of each type to the specified callback function. */ int ctf_type_iter(ctf_file_t *fp, ctf_type_f *func, void *arg) { ctf_id_t id, max = fp->ctf_typemax; int rc, child = (fp->ctf_flags & LCTF_CHILD); + int isroot; for (id = 1; id <= max; id++) { - const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR(fp, id); - if (CTF_INFO_ISROOT(tp->ctt_info) && - (rc = func(CTF_INDEX_TO_TYPE(id, child), arg)) != 0) + const void *tp = LCTF_INDEX_TO_TYPEPTR(fp, id); + ctf_get_ctt_info(fp, tp, NULL, NULL, &isroot); + if (isroot && + (rc = func(LCTF_INDEX_TO_TYPE(fp, id, child), arg)) != 0) return (rc); } return (0); } /* * Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and * RESTRICT nodes until we reach a "base" type node. This is useful when * we want to follow a type ID to a node that has members or a size. To guard * against infinite loops, we implement simplified cycle detection and check * each link against itself, the previous node, and the topmost node. */ ctf_id_t ctf_type_resolve(ctf_file_t *fp, ctf_id_t type) { ctf_id_t prev = type, otype = type; ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; + uint_t kind, ctype; while ((tp = ctf_lookup_by_id(&fp, type)) != NULL) { - switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + switch (kind) { case CTF_K_TYPEDEF: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: - if (tp->ctt_type == type || tp->ctt_type == otype || - tp->ctt_type == prev) { + ctf_get_ctt_index(fp, tp, NULL, &ctype, NULL); + if (ctype == type || ctype == otype || ctype == prev) { ctf_dprintf("type %ld cycle detected\n", otype); return (ctf_set_errno(ofp, ECTF_CORRUPT)); } prev = type; - type = tp->ctt_type; + type = ctype; break; default: return (type); } } return (CTF_ERR); /* errno is set for us */ } /* * Lookup the given type ID and print a string name for it into buf. Return * the actual number of bytes (not including \0) needed to format the name. */ static ssize_t ctf_type_qlname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len, const char *qname) { ctf_decl_t cd; ctf_decl_node_t *cdp; ctf_decl_prec_t prec, lp, rp; int ptr, arr; uint_t k; if (fp == NULL && type == CTF_ERR) return (-1); /* simplify caller code by permitting CTF_ERR */ ctf_decl_init(&cd, buf, len); ctf_decl_push(&cd, fp, type); if (cd.cd_err != 0) { ctf_decl_fini(&cd); return (ctf_set_errno(fp, cd.cd_err)); } /* * If the type graph's order conflicts with lexical precedence order * for pointers or arrays, then we need to surround the declarations at * the corresponding lexical precedence with parentheses. This can * result in either a parenthesized pointer (*) as in int (*)() or * int (*)[], or in a parenthesized pointer and array as in int (*[])(). */ ptr = cd.cd_order[CTF_PREC_POINTER] > CTF_PREC_POINTER; arr = cd.cd_order[CTF_PREC_ARRAY] > CTF_PREC_ARRAY; rp = arr ? CTF_PREC_ARRAY : ptr ? CTF_PREC_POINTER : -1; lp = ptr ? CTF_PREC_POINTER : arr ? CTF_PREC_ARRAY : -1; k = CTF_K_POINTER; /* avoid leading whitespace (see below) */ for (prec = CTF_PREC_BASE; prec < CTF_PREC_MAX; prec++) { for (cdp = ctf_list_next(&cd.cd_nodes[prec]); cdp != NULL; cdp = ctf_list_next(cdp)) { ctf_file_t *rfp = fp; - const ctf_type_t *tp = - ctf_lookup_by_id(&rfp, cdp->cd_type); - const char *name = ctf_strptr(rfp, tp->ctt_name); + const void *tp = ctf_lookup_by_id(&rfp, cdp->cd_type); + const char *name = ctf_type_rname(rfp, tp); if (k != CTF_K_POINTER && k != CTF_K_ARRAY) ctf_decl_sprintf(&cd, " "); if (lp == prec) { ctf_decl_sprintf(&cd, "("); lp = -1; } switch (cdp->cd_kind) { case CTF_K_INTEGER: case CTF_K_FLOAT: case CTF_K_TYPEDEF: if (qname != NULL) ctf_decl_sprintf(&cd, "%s`", qname); ctf_decl_sprintf(&cd, "%s", name); break; case CTF_K_POINTER: ctf_decl_sprintf(&cd, "*"); break; case CTF_K_ARRAY: ctf_decl_sprintf(&cd, "[%u]", cdp->cd_n); break; case CTF_K_FUNCTION: ctf_decl_sprintf(&cd, "()"); break; case CTF_K_STRUCT: case CTF_K_FORWARD: ctf_decl_sprintf(&cd, "struct "); if (qname != NULL) ctf_decl_sprintf(&cd, "%s`", qname); ctf_decl_sprintf(&cd, "%s", name); break; case CTF_K_UNION: ctf_decl_sprintf(&cd, "union "); if (qname != NULL) ctf_decl_sprintf(&cd, "%s`", qname); ctf_decl_sprintf(&cd, "%s", name); break; case CTF_K_ENUM: ctf_decl_sprintf(&cd, "enum "); if (qname != NULL) ctf_decl_sprintf(&cd, "%s`", qname); ctf_decl_sprintf(&cd, "%s", name); break; case CTF_K_VOLATILE: ctf_decl_sprintf(&cd, "volatile"); break; case CTF_K_CONST: ctf_decl_sprintf(&cd, "const"); break; case CTF_K_RESTRICT: ctf_decl_sprintf(&cd, "restrict"); break; } k = cdp->cd_kind; } if (rp == prec) ctf_decl_sprintf(&cd, ")"); } if (cd.cd_len >= len) (void) ctf_set_errno(fp, ECTF_NAMELEN); ctf_decl_fini(&cd); return (cd.cd_len); } ssize_t ctf_type_lname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len) { return (ctf_type_qlname(fp, type, buf, len, NULL)); } /* * Lookup the given type ID and print a string name for it into buf. If buf * is too small, return NULL: the ECTF_NAMELEN error is set on 'fp' for us. */ char * ctf_type_name(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len) { ssize_t rv = ctf_type_qlname(fp, type, buf, len, NULL); return (rv >= 0 && rv < len ? buf : NULL); } char * ctf_type_qname(ctf_file_t *fp, ctf_id_t type, char *buf, size_t len, const char *qname) { ssize_t rv = ctf_type_qlname(fp, type, buf, len, qname); return (rv >= 0 && rv < len ? buf : NULL); } +const char * +ctf_type_rname(ctf_file_t *fp, const void *v) +{ + uint_t name; + + if (fp->ctf_version == CTF_VERSION_2) { + const struct ctf_type_v2 *ctt = v; + + name = ctt->ctt_name; + } else { + const struct ctf_type_v3 *ctt = v; + + name = ctt->ctt_name; + } + + return (ctf_strptr(fp, name)); +} /* * Resolve the type down to a base type node, and then return the size * of the type storage in bytes. */ ssize_t ctf_type_size(ctf_file_t *fp, ctf_id_t type) { - const ctf_type_t *tp; + const void *tp; ssize_t size; ctf_arinfo_t ar; + uint_t kind; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (-1); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (-1); /* errno is set for us */ - switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + + switch (kind) { case CTF_K_POINTER: return (fp->ctf_dmodel->ctd_pointer); case CTF_K_FUNCTION: return (0); /* function size is only known by symtab */ case CTF_K_ENUM: return (fp->ctf_dmodel->ctd_int); case CTF_K_ARRAY: /* * Array size is not directly returned by stabs data. Instead, * it defines the element type and requires the user to perform * the multiplication. If ctf_get_ctt_size() returns zero, the * current version of ctfconvert does not compute member sizes * and we compute the size here on its behalf. */ if ((size = ctf_get_ctt_size(fp, tp, NULL, NULL)) > 0) return (size); if (ctf_array_info(fp, type, &ar) == CTF_ERR || (size = ctf_type_size(fp, ar.ctr_contents)) == CTF_ERR) return (-1); /* errno is set for us */ return (size * ar.ctr_nelems); default: return (ctf_get_ctt_size(fp, tp, NULL, NULL)); } } /* * Resolve the type down to a base type node, and then return the alignment * needed for the type storage in bytes. */ ssize_t ctf_type_align(ctf_file_t *fp, ctf_id_t type) { - const ctf_type_t *tp; + const void *tp; ctf_arinfo_t r; + uint_t kind, vlen; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (-1); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (-1); /* errno is set for us */ - switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); + + switch (kind) { case CTF_K_POINTER: case CTF_K_FUNCTION: return (fp->ctf_dmodel->ctd_pointer); case CTF_K_ARRAY: if (ctf_array_info(fp, type, &r) == CTF_ERR) return (-1); /* errno is set for us */ return (ctf_type_align(fp, r.ctr_contents)); case CTF_K_STRUCT: case CTF_K_UNION: { - uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info); + uint_t n = vlen; ssize_t size, increment; size_t align = 0; const void *vmp; (void) ctf_get_ctt_size(fp, tp, &size, &increment); vmp = (uchar_t *)tp + increment; - if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT) + if (kind == CTF_K_STRUCT) n = MIN(n, 1); /* only use first member for structs */ - if (size < CTF_LSTRUCT_THRESH) { - const ctf_member_t *mp = vmp; - for (; n != 0; n--, mp++) { - ssize_t am = ctf_type_align(fp, mp->ctm_type); - align = MAX(align, am); - } - } else { - const ctf_lmember_t *lmp = vmp; - for (; n != 0; n--, lmp++) { - ssize_t am = ctf_type_align(fp, lmp->ctlm_type); - align = MAX(align, am); - } + for (const char *mp = vmp; n != 0; n--, mp += increment) { + uint_t type; + + ctf_get_ctm_info(fp, mp, size, &increment, &type, + NULL, NULL); + ssize_t am = ctf_type_align(fp, type); + align = MAX(align, am); } return (align); } case CTF_K_ENUM: return (fp->ctf_dmodel->ctd_int); default: return (ctf_get_ctt_size(fp, tp, NULL, NULL)); } } /* * Return the kind (CTF_K_* constant) for the specified type ID. */ int ctf_type_kind(ctf_file_t *fp, ctf_id_t type) { - const ctf_type_t *tp; + const void *tp; + uint_t kind; if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ - return (LCTF_INFO_KIND(fp, tp->ctt_info)); + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + + return (kind); } /* * If the type is one that directly references another type (such as POINTER), * then return the ID of the type to which it refers. */ ctf_id_t ctf_type_reference(ctf_file_t *fp, ctf_id_t type) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; + uint_t ctype, kind; if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ - switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + + switch (kind) { case CTF_K_POINTER: case CTF_K_TYPEDEF: case CTF_K_VOLATILE: case CTF_K_CONST: case CTF_K_RESTRICT: - return (tp->ctt_type); + ctf_get_ctt_index(fp, tp, NULL, &ctype, NULL); + return (ctype); default: return (ctf_set_errno(ofp, ECTF_NOTREF)); } } /* * Find a pointer to type by looking in fp->ctf_ptrtab. If we can't find a * pointer to the given type, see if we can compute a pointer to the type * resulting from resolving the type down to its base type and use that * instead. This helps with cases where the CTF data includes "struct foo *" * but not "foo_t *" and the user accesses "foo_t *" in the debugger. */ ctf_id_t ctf_type_pointer(ctf_file_t *fp, ctf_id_t type) { ctf_file_t *ofp = fp; ctf_id_t ntype; if (ctf_lookup_by_id(&fp, type) == NULL) return (CTF_ERR); /* errno is set for us */ - if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0) - return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD))); + if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX(fp, type)]) != 0) + return (LCTF_INDEX_TO_TYPE(fp, ntype, (fp->ctf_flags & LCTF_CHILD))); if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (ctf_set_errno(ofp, ECTF_NOTYPE)); if (ctf_lookup_by_id(&fp, type) == NULL) return (ctf_set_errno(ofp, ECTF_NOTYPE)); - if ((ntype = fp->ctf_ptrtab[CTF_TYPE_TO_INDEX(type)]) != 0) - return (CTF_INDEX_TO_TYPE(ntype, (fp->ctf_flags & LCTF_CHILD))); + if ((ntype = fp->ctf_ptrtab[LCTF_TYPE_TO_INDEX(fp, type)]) != 0) + return (LCTF_INDEX_TO_TYPE(fp, ntype, (fp->ctf_flags & LCTF_CHILD))); return (ctf_set_errno(ofp, ECTF_NOTYPE)); } /* * Return the encoding for the specified INTEGER or FLOAT. */ int ctf_type_encoding(ctf_file_t *fp, ctf_id_t type, ctf_encoding_t *ep) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; ssize_t increment; - uint_t data; + uint_t data, kind; if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ (void) ctf_get_ctt_size(fp, tp, NULL, &increment); + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); - switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { + switch (kind) { case CTF_K_INTEGER: data = *(const uint_t *)((uintptr_t)tp + increment); ep->cte_format = CTF_INT_ENCODING(data); ep->cte_offset = CTF_INT_OFFSET(data); ep->cte_bits = CTF_INT_BITS(data); break; case CTF_K_FLOAT: data = *(const uint_t *)((uintptr_t)tp + increment); ep->cte_format = CTF_FP_ENCODING(data); ep->cte_offset = CTF_FP_OFFSET(data); ep->cte_bits = CTF_FP_BITS(data); break; default: return (ctf_set_errno(ofp, ECTF_NOTINTFP)); } return (0); } int ctf_type_cmp(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype) { int rval; if (ltype < rtype) rval = -1; else if (ltype > rtype) rval = 1; else rval = 0; if (lfp == rfp) return (rval); - if (CTF_TYPE_ISPARENT(ltype) && lfp->ctf_parent != NULL) + if (LCTF_TYPE_ISPARENT(lfp, ltype) && lfp->ctf_parent != NULL) lfp = lfp->ctf_parent; - if (CTF_TYPE_ISPARENT(rtype) && rfp->ctf_parent != NULL) + if (LCTF_TYPE_ISPARENT(rfp, rtype) && rfp->ctf_parent != NULL) rfp = rfp->ctf_parent; if (lfp < rfp) return (-1); if (lfp > rfp) return (1); return (rval); } /* * Return a boolean value indicating if two types are compatible integers or * floating-pointer values. This function returns true if the two types are * the same, or if they have the same ASCII name and encoding properties. * This function could be extended to test for compatibility for other kinds. */ int ctf_type_compat(ctf_file_t *lfp, ctf_id_t ltype, ctf_file_t *rfp, ctf_id_t rtype) { - const ctf_type_t *ltp, *rtp; + const void *ltp, *rtp; ctf_encoding_t le, re; ctf_arinfo_t la, ra; uint_t lkind, rkind; if (ctf_type_cmp(lfp, ltype, rfp, rtype) == 0) return (1); ltype = ctf_type_resolve(lfp, ltype); lkind = ctf_type_kind(lfp, ltype); rtype = ctf_type_resolve(rfp, rtype); rkind = ctf_type_kind(rfp, rtype); if (lkind != rkind || (ltp = ctf_lookup_by_id(&lfp, ltype)) == NULL || (rtp = ctf_lookup_by_id(&rfp, rtype)) == NULL || - strcmp(ctf_strptr(lfp, ltp->ctt_name), - ctf_strptr(rfp, rtp->ctt_name)) != 0) + strcmp(ctf_type_rname(lfp, ltp), ctf_type_rname(rfp, rtp)) != 0) return (0); switch (lkind) { case CTF_K_INTEGER: case CTF_K_FLOAT: return (ctf_type_encoding(lfp, ltype, &le) == 0 && ctf_type_encoding(rfp, rtype, &re) == 0 && bcmp(&le, &re, sizeof (ctf_encoding_t)) == 0); case CTF_K_POINTER: return (ctf_type_compat(lfp, ctf_type_reference(lfp, ltype), rfp, ctf_type_reference(rfp, rtype))); case CTF_K_ARRAY: return (ctf_array_info(lfp, ltype, &la) == 0 && ctf_array_info(rfp, rtype, &ra) == 0 && la.ctr_nelems == ra.ctr_nelems && ctf_type_compat( lfp, la.ctr_contents, rfp, ra.ctr_contents) && ctf_type_compat(lfp, la.ctr_index, rfp, ra.ctr_index)); case CTF_K_STRUCT: case CTF_K_UNION: return (ctf_type_size(lfp, ltype) == ctf_type_size(rfp, rtype)); case CTF_K_ENUM: case CTF_K_FORWARD: return (1); /* no other checks required for these type kinds */ default: return (0); /* should not get here since we did a resolve */ } } static int _ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name, ulong_t off, ctf_membinfo_t *mip) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; ssize_t size, increment; - uint_t kind, n; + uint_t kind, n, vlen; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ (void) ctf_get_ctt_size(fp, tp, &size, &increment); - kind = LCTF_INFO_KIND(fp, tp->ctt_info); + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno(ofp, ECTF_NOTSOU)); - if (size < CTF_LSTRUCT_THRESH) { - const ctf_member_t *mp = (const ctf_member_t *) - ((uintptr_t)tp + increment); - - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { - if (mp->ctm_name == 0 && - _ctf_member_info(fp, mp->ctm_type, name, - mp->ctm_offset + off, mip) == 0) - return (0); - if (strcmp(ctf_strptr(fp, mp->ctm_name), name) == 0) { - mip->ctm_type = mp->ctm_type; - mip->ctm_offset = mp->ctm_offset + off; - return (0); - } - } - } else { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) - ((uintptr_t)tp + increment); - - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { - if (lmp->ctlm_name == 0 && - _ctf_member_info(fp, lmp->ctlm_name, name, - (ulong_t)CTF_LMEM_OFFSET(lmp) + off, mip) == 0) - return (0); - if (strcmp(ctf_strptr(fp, lmp->ctlm_name), name) == 0) { - mip->ctm_type = lmp->ctlm_type; - mip->ctm_offset = - (ulong_t)CTF_LMEM_OFFSET(lmp) + off; - return (0); - } + const char *mp = (const char *)((uintptr_t)tp + increment); + + for (n = vlen; n != 0; n--, mp += increment) { + const char *name1; + ulong_t offset; + uint_t type; + + ctf_get_ctm_info(fp, mp, size, &increment, &type, &offset, + &name1); + if (name1 == NULL && + _ctf_member_info(fp, type, name1, offset + off, mip) == 0) + return (0); + if (strcmp(name1, name) == 0) { + mip->ctm_type = type; + mip->ctm_offset = offset + off; + return (0); } } return (ctf_set_errno(ofp, ECTF_NOMEMBNAM)); } /* * Return the type and offset for a given member of a STRUCT or UNION. */ int ctf_member_info(ctf_file_t *fp, ctf_id_t type, const char *name, ctf_membinfo_t *mip) { return (_ctf_member_info(fp, type, name, 0, mip)); } /* * Return the array type, index, and size information for the specified ARRAY. */ int ctf_array_info(ctf_file_t *fp, ctf_id_t type, ctf_arinfo_t *arp) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; - const ctf_array_t *ap; + const void *ap, *tp; ssize_t increment; + uint_t kind; if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ - if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ARRAY) + ctf_get_ctt_info(fp, tp, &kind, NULL, NULL); + + if (kind != CTF_K_ARRAY) return (ctf_set_errno(ofp, ECTF_NOTARRAY)); (void) ctf_get_ctt_size(fp, tp, NULL, &increment); - ap = (const ctf_array_t *)((uintptr_t)tp + increment); - arp->ctr_contents = ap->cta_contents; - arp->ctr_index = ap->cta_index; - arp->ctr_nelems = ap->cta_nelems; + ap = (const void *)((uintptr_t)tp + increment); + if (fp->ctf_version == CTF_VERSION_2) { + const struct ctf_array_v2 *ap2 = ap; + + arp->ctr_contents = ap2->cta_contents; + arp->ctr_index = ap2->cta_index; + arp->ctr_nelems = ap2->cta_nelems; + } else { + const struct ctf_array_v3 *ap3 = ap; + + arp->ctr_contents = ap3->cta_contents; + arp->ctr_index = ap3->cta_index; + arp->ctr_nelems = ap3->cta_nelems; + } return (0); } /* * Convert the specified value to the corresponding enum member name, if a * matching name can be found. Otherwise NULL is returned. */ const char * ctf_enum_name(ctf_file_t *fp, ctf_id_t type, int value) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; const ctf_enum_t *ep; ssize_t increment; - uint_t n; + uint_t kind, n, vlen; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (NULL); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (NULL); /* errno is set for us */ - if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) { + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); + + if (kind != CTF_K_ENUM) { (void) ctf_set_errno(ofp, ECTF_NOTENUM); return (NULL); } (void) ctf_get_ctt_size(fp, tp, NULL, &increment); ep = (const ctf_enum_t *)((uintptr_t)tp + increment); - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { + for (n = vlen; n != 0; n--, ep++) { if (ep->cte_value == value) return (ctf_strptr(fp, ep->cte_name)); } (void) ctf_set_errno(ofp, ECTF_NOENUMNAM); return (NULL); } /* * Convert the specified enum tag name to the corresponding value, if a * matching name can be found. Otherwise CTF_ERR is returned. */ int ctf_enum_value(ctf_file_t *fp, ctf_id_t type, const char *name, int *valp) { ctf_file_t *ofp = fp; - const ctf_type_t *tp; + const void *tp; const ctf_enum_t *ep; ssize_t size, increment; - uint_t n; + uint_t kind, n, vlen; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ - if (LCTF_INFO_KIND(fp, tp->ctt_info) != CTF_K_ENUM) { + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); + + if (kind != CTF_K_ENUM) { (void) ctf_set_errno(ofp, ECTF_NOTENUM); return (CTF_ERR); } (void) ctf_get_ctt_size(fp, tp, &size, &increment); ep = (const ctf_enum_t *)((uintptr_t)tp + increment); - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, ep++) { + for (n = vlen; n != 0; n--, ep++) { if (strcmp(ctf_strptr(fp, ep->cte_name), name) == 0) { if (valp != NULL) *valp = ep->cte_value; return (0); } } (void) ctf_set_errno(ofp, ECTF_NOENUMNAM); return (CTF_ERR); } /* * Recursively visit the members of any type. This function is used as the * engine for ctf_type_visit, below. We resolve the input type, recursively * invoke ourself for each type member if the type is a struct or union, and * then invoke the callback function on the current type. If any callback * returns non-zero, we abort and percolate the error code back up to the top. */ static int ctf_type_rvisit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg, const char *name, ulong_t offset, int depth) { ctf_id_t otype = type; - const ctf_type_t *tp; + const void *tp; ssize_t size, increment; - uint_t kind, n; + uint_t kind, n, vlen; int rc; if ((type = ctf_type_resolve(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((tp = ctf_lookup_by_id(&fp, type)) == NULL) return (CTF_ERR); /* errno is set for us */ if ((rc = func(name, otype, offset, depth, arg)) != 0) return (rc); - kind = LCTF_INFO_KIND(fp, tp->ctt_info); + ctf_get_ctt_info(fp, tp, &kind, &vlen, NULL); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (0); (void) ctf_get_ctt_size(fp, tp, &size, &increment); - if (size < CTF_LSTRUCT_THRESH) { - const ctf_member_t *mp = (const ctf_member_t *) - ((uintptr_t)tp + increment); + const char *mp = (const char *)((uintptr_t)tp + increment); + for (n = vlen; n != 0; n--, mp += increment) { + const char *name; + ulong_t offset1; + uint_t type; - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, mp++) { - if ((rc = ctf_type_rvisit(fp, mp->ctm_type, - func, arg, ctf_strptr(fp, mp->ctm_name), - offset + mp->ctm_offset, depth + 1)) != 0) - return (rc); - } - - } else { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) - ((uintptr_t)tp + increment); - - for (n = LCTF_INFO_VLEN(fp, tp->ctt_info); n != 0; n--, lmp++) { - if ((rc = ctf_type_rvisit(fp, lmp->ctlm_type, - func, arg, ctf_strptr(fp, lmp->ctlm_name), - offset + (ulong_t)CTF_LMEM_OFFSET(lmp), - depth + 1)) != 0) - return (rc); - } + ctf_get_ctm_info(fp, mp, size, &increment, &type, &offset1, + &name); + if ((rc = ctf_type_rvisit(fp, type, func, arg, name, + offset + offset1, depth + 1)) != 0) + return (rc); } return (0); } /* * Recursively visit the members of any type. We pass the name, member * type, and offset of each member to the specified callback function. */ int ctf_type_visit(ctf_file_t *fp, ctf_id_t type, ctf_visit_f *func, void *arg) { return (ctf_type_rvisit(fp, type, func, arg, "", 0, 0)); } diff --git a/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c b/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c index f48c09cce0e2..e1ba993a09a9 100644 --- a/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c +++ b/cddl/contrib/opensolaris/lib/libctf/common/ctf_lib.c @@ -1,529 +1,530 @@ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #ifdef illumos #include #else #include #endif #include #ifdef illumos #ifdef _LP64 static const char *_libctf_zlib = "/usr/lib/64/libz.so"; #else static const char *_libctf_zlib = "/usr/lib/libz.so"; #endif #endif static struct { int (*z_uncompress)(uchar_t *, ulong_t *, const uchar_t *, ulong_t); const char *(*z_error)(int); void *z_dlp; } zlib; static size_t _PAGESIZE; static size_t _PAGEMASK; #ifdef illumos #pragma init(_libctf_init) #else void _libctf_init(void) __attribute__ ((constructor)); #endif void _libctf_init(void) { #ifdef illumos const char *p = getenv("LIBCTF_DECOMPRESSOR"); if (p != NULL) _libctf_zlib = p; /* use alternate decompression library */ #endif _libctf_debug = getenv("LIBCTF_DEBUG") != NULL; _PAGESIZE = getpagesize(); _PAGEMASK = ~(_PAGESIZE - 1); } /* * Attempt to dlopen the decompression library and locate the symbols of * interest that we will need to call. This information in cached so * that multiple calls to ctf_bufopen() do not need to reopen the library. */ void * ctf_zopen(int *errp) { #ifdef illumos ctf_dprintf("decompressing CTF data using %s\n", _libctf_zlib); if (zlib.z_dlp != NULL) return (zlib.z_dlp); /* library is already loaded */ if (access(_libctf_zlib, R_OK) == -1) return (ctf_set_open_errno(errp, ECTF_ZMISSING)); if ((zlib.z_dlp = dlopen(_libctf_zlib, RTLD_LAZY | RTLD_LOCAL)) == NULL) return (ctf_set_open_errno(errp, ECTF_ZINIT)); zlib.z_uncompress = (int (*)(uchar_t *, ulong_t *, const uchar_t *, ulong_t)) dlsym(zlib.z_dlp, "uncompress"); zlib.z_error = (const char *(*)(int)) dlsym(zlib.z_dlp, "zError"); if (zlib.z_uncompress == NULL || zlib.z_error == NULL) { (void) dlclose(zlib.z_dlp); bzero(&zlib, sizeof (zlib)); return (ctf_set_open_errno(errp, ECTF_ZINIT)); } #else zlib.z_uncompress = uncompress; zlib.z_error = zError; /* Dummy return variable as 'no error' */ zlib.z_dlp = (void *) (uintptr_t) 1; #endif return (zlib.z_dlp); } /* * The ctf_bufopen() routine calls these subroutines, defined by , * which we then patch through to the functions in the decompression library. */ int z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen) { return (zlib.z_uncompress(dst, (ulong_t *)dstlen, src, srclen)); } const char * z_strerror(int err) { return (zlib.z_error(err)); } /* * Convert a 32-bit ELF file header into GElf. */ static void ehdr_to_gelf(const Elf32_Ehdr *src, GElf_Ehdr *dst) { bcopy(src->e_ident, dst->e_ident, EI_NIDENT); dst->e_type = src->e_type; dst->e_machine = src->e_machine; dst->e_version = src->e_version; dst->e_entry = (Elf64_Addr)src->e_entry; dst->e_phoff = (Elf64_Off)src->e_phoff; dst->e_shoff = (Elf64_Off)src->e_shoff; dst->e_flags = src->e_flags; dst->e_ehsize = src->e_ehsize; dst->e_phentsize = src->e_phentsize; dst->e_phnum = src->e_phnum; dst->e_shentsize = src->e_shentsize; dst->e_shnum = src->e_shnum; dst->e_shstrndx = src->e_shstrndx; } /* * Convert a 32-bit ELF section header into GElf. */ static void shdr_to_gelf(const Elf32_Shdr *src, GElf_Shdr *dst) { dst->sh_name = src->sh_name; dst->sh_type = src->sh_type; dst->sh_flags = src->sh_flags; dst->sh_addr = src->sh_addr; dst->sh_offset = src->sh_offset; dst->sh_size = src->sh_size; dst->sh_link = src->sh_link; dst->sh_info = src->sh_info; dst->sh_addralign = src->sh_addralign; dst->sh_entsize = src->sh_entsize; } /* * In order to mmap a section from the ELF file, we must round down sh_offset * to the previous page boundary, and mmap the surrounding page. We store * the pointer to the start of the actual section data back into sp->cts_data. */ const void * ctf_sect_mmap(ctf_sect_t *sp, int fd) { size_t pageoff = sp->cts_offset & ~_PAGEMASK; caddr_t base = mmap64(NULL, sp->cts_size + pageoff, PROT_READ, MAP_PRIVATE, fd, sp->cts_offset & _PAGEMASK); if (base != MAP_FAILED) sp->cts_data = base + pageoff; return (base); } /* * Since sp->cts_data has the adjusted offset, we have to again round down * to get the actual mmap address and round up to get the size. */ void ctf_sect_munmap(const ctf_sect_t *sp) { uintptr_t addr = (uintptr_t)sp->cts_data; uintptr_t pageoff = addr & ~_PAGEMASK; (void) munmap((void *)(addr - pageoff), sp->cts_size + pageoff); } /* * Open the specified file descriptor and return a pointer to a CTF container. * The file can be either an ELF file or raw CTF file. The caller is * responsible for closing the file descriptor when it is no longer needed. */ ctf_file_t * ctf_fdopen(int fd, int *errp) { ctf_sect_t ctfsect, symsect, strsect; ctf_file_t *fp = NULL; size_t shstrndx, shnum; struct stat64 st; ssize_t nbytes; union { ctf_preamble_t ctf; Elf32_Ehdr e32; GElf_Ehdr e64; } hdr; bzero(&ctfsect, sizeof (ctf_sect_t)); bzero(&symsect, sizeof (ctf_sect_t)); bzero(&strsect, sizeof (ctf_sect_t)); bzero(&hdr, sizeof (hdr)); if (fstat64(fd, &st) == -1) return (ctf_set_open_errno(errp, errno)); if ((nbytes = pread64(fd, &hdr, sizeof (hdr), 0)) <= 0) return (ctf_set_open_errno(errp, nbytes < 0? errno : ECTF_FMT)); /* * If we have read enough bytes to form a CTF header and the magic * string matches, attempt to interpret the file as raw CTF. */ if (nbytes >= (ssize_t) sizeof (ctf_preamble_t) && hdr.ctf.ctp_magic == CTF_MAGIC) { - if (hdr.ctf.ctp_version > CTF_VERSION) + if (hdr.ctf.ctp_version != CTF_VERSION_2 && + hdr.ctf.ctp_version != CTF_VERSION_3) return (ctf_set_open_errno(errp, ECTF_CTFVERS)); ctfsect.cts_data = mmap64(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (ctfsect.cts_data == MAP_FAILED) return (ctf_set_open_errno(errp, errno)); ctfsect.cts_name = _CTF_SECTION; ctfsect.cts_type = SHT_PROGBITS; ctfsect.cts_flags = SHF_ALLOC; ctfsect.cts_size = (size_t)st.st_size; ctfsect.cts_entsize = 1; ctfsect.cts_offset = 0; if ((fp = ctf_bufopen(&ctfsect, NULL, NULL, errp)) == NULL) ctf_sect_munmap(&ctfsect); return (fp); } /* * If we have read enough bytes to form an ELF header and the magic * string matches, attempt to interpret the file as an ELF file. We * do our own largefile ELF processing, and convert everything to * GElf structures so that clients can operate on any data model. */ if (nbytes >= (ssize_t) sizeof (Elf32_Ehdr) && bcmp(&hdr.e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { #if BYTE_ORDER == _BIG_ENDIAN uchar_t order = ELFDATA2MSB; #else uchar_t order = ELFDATA2LSB; #endif GElf_Shdr *sp; void *strs_map; size_t strs_mapsz, i; char *strs; if (hdr.e32.e_ident[EI_DATA] != order) return (ctf_set_open_errno(errp, ECTF_ENDIAN)); if (hdr.e32.e_version != EV_CURRENT) return (ctf_set_open_errno(errp, ECTF_ELFVERS)); if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS64) { if (nbytes < (ssize_t) sizeof (GElf_Ehdr)) return (ctf_set_open_errno(errp, ECTF_FMT)); } else { Elf32_Ehdr e32 = hdr.e32; ehdr_to_gelf(&e32, &hdr.e64); } shnum = hdr.e64.e_shnum; shstrndx = hdr.e64.e_shstrndx; /* Extended ELF sections */ if ((shstrndx == SHN_XINDEX) || (shnum == 0)) { if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { Elf32_Shdr x32; if (pread64(fd, &x32, sizeof (x32), hdr.e64.e_shoff) != sizeof (x32)) return (ctf_set_open_errno(errp, errno)); shnum = x32.sh_size; shstrndx = x32.sh_link; } else { Elf64_Shdr x64; if (pread64(fd, &x64, sizeof (x64), hdr.e64.e_shoff) != sizeof (x64)) return (ctf_set_open_errno(errp, errno)); shnum = x64.sh_size; shstrndx = x64.sh_link; } } if (shstrndx >= shnum) return (ctf_set_open_errno(errp, ECTF_CORRUPT)); nbytes = sizeof (GElf_Shdr) * shnum; if ((sp = malloc(nbytes)) == NULL) return (ctf_set_open_errno(errp, errno)); /* * Read in and convert to GElf the array of Shdr structures * from e_shoff so we can locate sections of interest. */ if (hdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { Elf32_Shdr *sp32; nbytes = sizeof (Elf32_Shdr) * shnum; if ((sp32 = malloc(nbytes)) == NULL || pread64(fd, sp32, nbytes, hdr.e64.e_shoff) != nbytes) { free(sp); free(sp32); return (ctf_set_open_errno(errp, errno)); } for (i = 0; i < shnum; i++) shdr_to_gelf(&sp32[i], &sp[i]); free(sp32); } else if (pread64(fd, sp, nbytes, hdr.e64.e_shoff) != nbytes) { free(sp); return (ctf_set_open_errno(errp, errno)); } /* * Now mmap the section header strings section so that we can * perform string comparison on the section names. */ strs_mapsz = sp[shstrndx].sh_size + (sp[shstrndx].sh_offset & ~_PAGEMASK); strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE, fd, sp[shstrndx].sh_offset & _PAGEMASK); strs = (char *)strs_map + (sp[shstrndx].sh_offset & ~_PAGEMASK); if (strs_map == MAP_FAILED) { free(sp); return (ctf_set_open_errno(errp, ECTF_MMAP)); } /* * Iterate over the section header array looking for the CTF * section and symbol table. The strtab is linked to symtab. */ for (i = 0; i < shnum; i++) { const GElf_Shdr *shp = &sp[i]; const GElf_Shdr *lhp = &sp[shp->sh_link]; if (shp->sh_link >= shnum) continue; /* corrupt sh_link field */ if (shp->sh_name >= sp[shstrndx].sh_size || lhp->sh_name >= sp[shstrndx].sh_size) continue; /* corrupt sh_name field */ if (shp->sh_type == SHT_PROGBITS && strcmp(strs + shp->sh_name, _CTF_SECTION) == 0) { ctfsect.cts_name = strs + shp->sh_name; ctfsect.cts_type = shp->sh_type; ctfsect.cts_flags = shp->sh_flags; ctfsect.cts_size = shp->sh_size; ctfsect.cts_entsize = shp->sh_entsize; ctfsect.cts_offset = (off64_t)shp->sh_offset; } else if (shp->sh_type == SHT_SYMTAB) { symsect.cts_name = strs + shp->sh_name; symsect.cts_type = shp->sh_type; symsect.cts_flags = shp->sh_flags; symsect.cts_size = shp->sh_size; symsect.cts_entsize = shp->sh_entsize; symsect.cts_offset = (off64_t)shp->sh_offset; strsect.cts_name = strs + lhp->sh_name; strsect.cts_type = lhp->sh_type; strsect.cts_flags = lhp->sh_flags; strsect.cts_size = lhp->sh_size; strsect.cts_entsize = lhp->sh_entsize; strsect.cts_offset = (off64_t)lhp->sh_offset; } } free(sp); /* free section header array */ if (ctfsect.cts_type == SHT_NULL) { (void) munmap(strs_map, strs_mapsz); return (ctf_set_open_errno(errp, ECTF_NOCTFDATA)); } /* * Now mmap the CTF data, symtab, and strtab sections and * call ctf_bufopen() to do the rest of the work. */ if (ctf_sect_mmap(&ctfsect, fd) == MAP_FAILED) { (void) munmap(strs_map, strs_mapsz); return (ctf_set_open_errno(errp, ECTF_MMAP)); } if (symsect.cts_type != SHT_NULL && strsect.cts_type != SHT_NULL) { if (ctf_sect_mmap(&symsect, fd) == MAP_FAILED || ctf_sect_mmap(&strsect, fd) == MAP_FAILED) { (void) ctf_set_open_errno(errp, ECTF_MMAP); goto bad; /* unmap all and abort */ } fp = ctf_bufopen(&ctfsect, &symsect, &strsect, errp); } else fp = ctf_bufopen(&ctfsect, NULL, NULL, errp); bad: if (fp == NULL) { ctf_sect_munmap(&ctfsect); ctf_sect_munmap(&symsect); ctf_sect_munmap(&strsect); } else fp->ctf_flags |= LCTF_MMAP; (void) munmap(strs_map, strs_mapsz); return (fp); } return (ctf_set_open_errno(errp, ECTF_FMT)); } /* * Open the specified file and return a pointer to a CTF container. The file * can be either an ELF file or raw CTF file. This is just a convenient * wrapper around ctf_fdopen() for callers. */ ctf_file_t * ctf_open(const char *filename, int *errp) { ctf_file_t *fp; int fd; if ((fd = open64(filename, O_RDONLY)) == -1) { if (errp != NULL) *errp = errno; return (NULL); } fp = ctf_fdopen(fd, errp); (void) close(fd); return (fp); } /* * Write the uncompressed CTF data stream to the specified file descriptor. * This is useful for saving the results of dynamic CTF containers. */ int ctf_write(ctf_file_t *fp, int fd) { const uchar_t *buf = fp->ctf_base; ssize_t resid = fp->ctf_size; ssize_t len; while (resid != 0) { if ((len = write(fd, buf, resid)) <= 0) return (ctf_set_errno(fp, errno)); resid -= len; buf += len; } return (0); } /* * Set the CTF library client version to the specified version. If version is * zero, we just return the default library version number. */ int ctf_version(int version) { if (version < 0) { errno = EINVAL; return (-1); } if (version > 0) { if (version > CTF_VERSION) { errno = ENOTSUP; return (-1); } ctf_dprintf("ctf_version: client using version %d\n", version); _libctf_version = version; } return (_libctf_version); }