Example #1
0
/**
 * Releases the kernel module and closes its CTF data.
 *
 * @param pMod          Pointer to the module handle.
 * @param pCTF          Pointer to the module's CTF handle.
 */
static void rtR0DbgKrnlInfoModRelease(modctl_t *pMod, ctf_file_t *pCTF)
{
    AssertPtrReturnVoid(pMod);
    AssertPtrReturnVoid(pCTF);

    ctf_close(pCTF);
}
Example #2
0
/*ARGSUSED*/
void
dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	ctf_close(dmp->dm_ctfp);
	dmp->dm_ctfp = NULL;

	bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
	bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
	bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));

	if (dmp->dm_symbuckets != NULL) {
		free(dmp->dm_symbuckets);
		dmp->dm_symbuckets = NULL;
	}

	if (dmp->dm_symchains != NULL) {
		free(dmp->dm_symchains);
		dmp->dm_symchains = NULL;
	}

	if (dmp->dm_asmap != NULL) {
		free(dmp->dm_asmap);
		dmp->dm_asmap = NULL;
	}

	dmp->dm_symfree = 0;
	dmp->dm_nsymbuckets = 0;
	dmp->dm_nsymelems = 0;
	dmp->dm_asrsv = 0;
	dmp->dm_aslen = 0;

	dmp->dm_text_va = (GElf_Addr)0;
	dmp->dm_text_size = 0;
	dmp->dm_data_va = (GElf_Addr)0;
	dmp->dm_data_size = 0;
	dmp->dm_bss_va = (GElf_Addr)0;
	dmp->dm_bss_size = 0;

	if (dmp->dm_extern != NULL) {
		dt_idhash_destroy(dmp->dm_extern);
		dmp->dm_extern = NULL;
	}

	(void) elf_end(dmp->dm_elf);
	dmp->dm_elf = NULL;

	dmp->dm_flags &= ~DT_DM_LOADED;
}
Example #3
0
int
kctl_mod_decompress(struct modctl *modp)
{
	ctf_file_t *fp;
	struct module *mp = modp->mod_mp;
	int rc;

	if ((kmdb_kdi_get_flags() & KMDB_KDI_FL_NOCTF) || mp->ctfdata == NULL)
		return (0);

	if ((fp = ctf_modopen(mp, &rc)) == NULL)
		return (rc);

	ctf_close(fp);

	return (0);
}
Example #4
0
/*
 * 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);
}
Example #5
0
/*
 * Called by the kmdb_kvm target upon debugger reentry, this routine checks
 * to see if the loaded dmods have changed.  Of particular interest is the
 * exportation of dmod symbol tables, which will happen during the boot
 * process for dmods that were loaded prior to kernel startup.  If this
 * has occurred, we'll need to reconstruct our view of the symbol tables for
 * the affected dmods, since the old symbol tables lived in bootmem
 * and have been moved during the kobj_export_module().
 *
 * Also, any ctf_file_t we might have opened is now invalid, since it
 * has internal pointers to the old data as well.
 */
void
kmdb_module_sync(void)
{
    mdb_var_t *v;

    mdb_nv_rewind(&mdb.m_dmodctl);
    while ((v = mdb_nv_advance(&mdb.m_dmodctl)) != NULL) {
        kmdb_modctl_t *kmc = MDB_NV_COOKIE(v);
        struct module *mp;

        if (kmc->kmc_state != KMDB_MC_STATE_LOADED)
            continue;

        mp = kmc->kmc_modctl->mod_mp;

        if ((mp->flags & (KOBJ_PRIM | KOBJ_EXPORTED)) &&
                !kmc->kmc_exported) {
            /*
             * The exporting process moves the symtab from boot
             * scratch memory to vmem.
             */
            if (kmc->kmc_symtab != NULL)
                mdb_gelf_symtab_destroy(kmc->kmc_symtab);

            kmc->kmc_symtab = mdb_gelf_symtab_create_raw(
                                  &kmc->kmc_ehdr, mp->symhdr, mp->symtbl, mp->strhdr,
                                  mp->strings, MDB_TGT_SYMTAB);

            if (kmc->kmc_mod->mod_ctfp != NULL) {
                ctf_close(kmc->kmc_mod->mod_ctfp);
                kmc->kmc_mod->mod_ctfp =
                    mdb_ctf_open(kmc->kmc_modname, NULL);
            }
            kmc->kmc_exported = TRUE;
        }
    }
}
Example #6
0
/*
 * 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);

	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
		ntd = ctf_list_next(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));
	}

	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));
}
Example #7
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 (struct nlist) &&
	    symsect->cts_entsize != sizeof (struct nlist_64))
		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 (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 if (pp->ctp_version == CTF_VERSION_1) {
		const ctf_header_v1_t *h1p =
		    (const ctf_header_v1_t *)ctfsect->cts_data;

		if (ctfsect->cts_size < sizeof (ctf_header_v1_t))
			return (ctf_set_open_errno(errp, ECTF_NOCTFBUF));

		bzero(&hp, sizeof (hp));
		hp.cth_preamble = h1p->cth_preamble;
		hp.cth_objtoff = h1p->cth_objtoff;
		hp.cth_funcoff = h1p->cth_funcoff;
		hp.cth_typeoff = h1p->cth_typeoff;
		hp.cth_stroff = h1p->cth_stroff;
		hp.cth_strlen = h1p->cth_strlen;

		hdrsz = sizeof (ctf_header_v1_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_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 : "<NULL>",
	    fp->ctf_parlabel ? fp->ctf_parlabel : "<NULL>");

	/*
	 * 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 (struct nlist_64))
			(void) ctf_setmodel(fp, CTF_MODEL_LP64);
		else if (symsect->cts_entsize == sizeof (struct nlist))
			(void) ctf_setmodel(fp, CTF_MODEL_ILP32);
		else 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);
}
Example #8
0
/*
 * 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;

	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);

		if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT)
			size += sizeof (ctf_stype_t);
		else
			size += sizeof (ctf_type_t);

		switch (kind) {
		case CTF_K_INTEGER:
		case CTF_K_FLOAT:
			size += sizeof (uint_t);
			break;
		case CTF_K_ARRAY:
			size += sizeof (ctf_array_t);
			break;
		case CTF_K_FUNCTION:
			size += sizeof (ushort_t) * (vlen + (vlen & 1));
			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;
			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)) {

		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);

		bcopy(&dtd->dtd_data, 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);
			break;

		case CTF_K_FUNCTION: {
			ushort_t *argv = (ushort_t *)(uintptr_t)t;
			uint_t argc;

			for (argc = 0; argc < vlen; argc++)
				*argv++ = (ushort_t)dtd->dtd_u.dtu_argv[argc];

			if (vlen & 1)
				*argv++ = 0; /* pad to 4-byte boundary */

			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);
			else
				t = ctf_copy_lmembers(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);
}
Example #9
0
/*ARGSUSED*/
void
dt_module_unload(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	int i;

	ctf_close(dmp->dm_ctfp);
	dmp->dm_ctfp = NULL;

#if !defined(sun)
	if (dmp->dm_ctdata.cts_data != NULL) {
		free(dmp->dm_ctdata.cts_data);
	}
	if (dmp->dm_symtab.cts_data != NULL) {
		free(dmp->dm_symtab.cts_data);
	}
	if (dmp->dm_strtab.cts_data != NULL) {
		free(dmp->dm_strtab.cts_data);
	}
#endif

	if (dmp->dm_libctfp != NULL) {
		for (i = 0; i < dmp->dm_nctflibs; i++) {
			ctf_close(dmp->dm_libctfp[i]);
			free(dmp->dm_libctfn[i]);
		}
		free(dmp->dm_libctfp);
		free(dmp->dm_libctfn);
		dmp->dm_libctfp = NULL;
		dmp->dm_nctflibs = 0;
	}

	bzero(&dmp->dm_ctdata, sizeof (ctf_sect_t));
	bzero(&dmp->dm_symtab, sizeof (ctf_sect_t));
	bzero(&dmp->dm_strtab, sizeof (ctf_sect_t));

	if (dmp->dm_symbuckets != NULL) {
		free(dmp->dm_symbuckets);
		dmp->dm_symbuckets = NULL;
	}

	if (dmp->dm_symchains != NULL) {
		free(dmp->dm_symchains);
		dmp->dm_symchains = NULL;
	}

	if (dmp->dm_asmap != NULL) {
		free(dmp->dm_asmap);
		dmp->dm_asmap = NULL;
	}
#if defined(__FreeBSD__)
	if (dmp->dm_sec_offsets != NULL) {
		free(dmp->dm_sec_offsets);
		dmp->dm_sec_offsets = NULL;
	}
#endif
	dmp->dm_symfree = 0;
	dmp->dm_nsymbuckets = 0;
	dmp->dm_nsymelems = 0;
	dmp->dm_asrsv = 0;
	dmp->dm_aslen = 0;

	dmp->dm_text_va = 0;
	dmp->dm_text_size = 0;
	dmp->dm_data_va = 0;
	dmp->dm_data_size = 0;
	dmp->dm_bss_va = 0;
	dmp->dm_bss_size = 0;

	if (dmp->dm_extern != NULL) {
		dt_idhash_destroy(dmp->dm_extern);
		dmp->dm_extern = NULL;
	}

	(void) elf_end(dmp->dm_elf);
	dmp->dm_elf = NULL;

	dmp->dm_pid = 0;

	dmp->dm_flags &= ~DT_DM_LOADED;
}
Example #10
0
ctf_file_t *
dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	const char *parent;
	dt_module_t *pmp;
	ctf_file_t *pfp;
	int model;

	if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0)
		return (dmp->dm_ctfp);

	if (dmp->dm_ops == &dt_modops_64)
		model = CTF_MODEL_LP64;
	else
		model = CTF_MODEL_ILP32;

	/*
	 * If the data model of the module does not match our program data
	 * model, then do not permit CTF from this module to be opened and
	 * returned to the compiler.  If we support mixed data models in the
	 * future for combined kernel/user tracing, this can be removed.
	 */
	if (dtp->dt_conf.dtc_ctfmodel != model) {
		(void) dt_set_errno(dtp, EDT_DATAMODEL);
		return (NULL);
	}

	if (dmp->dm_ctdata.cts_size == 0) {
		(void) dt_set_errno(dtp, EDT_NOCTF);
		return (NULL);
	}

	dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata,
	    &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr);

	if (dmp->dm_ctfp == NULL) {
		(void) dt_set_errno(dtp, EDT_CTF);
		return (NULL);
	}

	(void) ctf_setmodel(dmp->dm_ctfp, model);
	ctf_setspecific(dmp->dm_ctfp, dmp);

	if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) {
		if ((pmp = dt_module_create(dtp, parent)) == NULL ||
		    (pfp = dt_module_getctf(dtp, pmp)) == NULL) {
			if (pmp == NULL)
				(void) dt_set_errno(dtp, EDT_NOMEM);
			goto err;
		}

		if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) {
			dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
			(void) dt_set_errno(dtp, EDT_CTF);
			goto err;
		}
	}

	dt_dprintf("loaded CTF container for %s (%p)\n",
	    dmp->dm_name, (void *)dmp->dm_ctfp);

	return (dmp->dm_ctfp);

err:
	ctf_close(dmp->dm_ctfp);
	dmp->dm_ctfp = NULL;
	return (NULL);
}
Example #11
0
ctf_file_t *
dt_module_getctf(dtrace_hdl_t *dtp, dt_module_t *dmp)
{
	const char *parent;
	dt_module_t *pmp;
	ctf_file_t *pfp;
	int model;

	if (dmp->dm_ctfp != NULL || dt_module_load(dtp, dmp) != 0)
		return (dmp->dm_ctfp);

	if (dmp->dm_ops == &dt_modops_macho_64)
		model = CTF_MODEL_LP64;
	else if (dmp->dm_ops == &dt_modops_macho_32)
		model = CTF_MODEL_ILP32;
	else
	if (dmp->dm_ops == &dt_modops_64)
		model = CTF_MODEL_LP64;
	else
		model = CTF_MODEL_ILP32;

	if (dmp->dm_ctdata.cts_size == 0) {
		(void) dt_set_errno(dtp, EDT_NOCTF);
		return (NULL);
	}

	dmp->dm_ctfp = ctf_bufopen(&dmp->dm_ctdata,
	    &dmp->dm_symtab, &dmp->dm_strtab, &dtp->dt_ctferr);

	if (dmp->dm_ctfp == NULL) {
		(void) dt_set_errno(dtp, EDT_CTF);
		return (NULL);
	}

	(void) ctf_setmodel(dmp->dm_ctfp, model);
	ctf_setspecific(dmp->dm_ctfp, dmp);

	if ((parent = ctf_parent_name(dmp->dm_ctfp)) != NULL) {
		if ((pmp = dt_module_create(dtp, parent)) == NULL ||
		    (pfp = dt_module_getctf(dtp, pmp)) == NULL) {
			if (pmp == NULL)
				(void) dt_set_errno(dtp, EDT_NOMEM);
			goto err;
		}

		if (ctf_import(dmp->dm_ctfp, pfp) == CTF_ERR) {
			dtp->dt_ctferr = ctf_errno(dmp->dm_ctfp);
			(void) dt_set_errno(dtp, EDT_CTF);
			goto err;
		}
	}

	dt_dprintf("loaded CTF container for %s (%p)\n",
	    dmp->dm_name, (void *)dmp->dm_ctfp);

	return (dmp->dm_ctfp);

err:
	ctf_close(dmp->dm_ctfp);
	dmp->dm_ctfp = NULL;
	return (NULL);
}
Example #12
0
/*
 * 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;
	ctf_dmdef_t *dmd, *nmd;

	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;
	}

	for (dtd = ctf_list_next(&fp->ctf_dtdefs); dtd != NULL; dtd = ntd) {
		switch (CTF_INFO_KIND(dtd->dtd_data.ctt_info)) {
		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) {
					ctf_free(dmd->dmd_name,
					    strlen(dmd->dmd_name) + 1);
				}
				nmd = ctf_list_next(dmd);
				ctf_free(dmd, sizeof (ctf_dmdef_t));
			}
			break;
		case CTF_K_FUNCTION:
			ctf_free(dtd->dtd_u.dtu_argv, sizeof (ctf_id_t) *
			    CTF_INFO_VLEN(dtd->dtd_data.ctt_info));
			break;
		}

		if (dtd->dtd_name != NULL)
			ctf_free(dtd->dtd_name, strlen(dtd->dtd_name) + 1);

		ntd = ctf_list_next(dtd);
		ctf_free(dtd, sizeof (ctf_dtdef_t));
	}

	if (fp->ctf_parent != NULL)
		ctf_close(fp->ctf_parent);

	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));
	}

	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));
}
Example #13
0
/*ARGSUSED*/
static void
fbt_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
{
	fbt_probe_t *fbt = parg;
	struct modctl *ctl = fbt->fbtp_ctl;
	struct module *mp = ctl->mod_mp;
	ctf_file_t *fp = NULL, *pfp;
	ctf_funcinfo_t f;
	int error;
	ctf_id_t argv[32], type;
	int argc = sizeof (argv) / sizeof (ctf_id_t);
	const char *parent;

	if (!ctl->mod_loaded || (ctl->mod_loadcnt != fbt->fbtp_loadcnt))
		goto err;

	if (fbt->fbtp_roffset != 0 && desc->dtargd_ndx == 0) {
		(void) strlcpy(desc->dtargd_native, "int",
			       sizeof(desc->dtargd_native));
		return;
	}

	if ((fp = ctf_modopen(mp, &error)) == NULL) {
		/*
		 * We have no CTF information for this module -- and therefore
		 * no args[] information.
		 */
		goto err;
	}

	/*
	 * If we have a parent container, we must manually import it.
	 */
	if ((parent = ctf_parent_name(fp)) != NULL) {
		struct modctl *mp = &modules;
		struct modctl *mod = NULL;

		/*
		 * We must iterate over all modules to find the module that
		 * is our parent.
		 */
		do {
			if (strcmp(mp->mod_modname, parent) == 0) {
				mod = mp;
				break;
			}
		} while ((mp = mp->mod_next) != &modules);

		if (mod == NULL)
			goto err;

		if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL) {
			goto err;
		}

		if (ctf_import(fp, pfp) != 0) {
			ctf_close(pfp);
			goto err;
		}

		ctf_close(pfp);
	}

	if (ctf_func_info(fp, fbt->fbtp_symndx, &f) == CTF_ERR)
		goto err;

	if (fbt->fbtp_roffset != 0) {
		if (desc->dtargd_ndx > 1)
			goto err;

		ASSERT(desc->dtargd_ndx == 1);
		type = f.ctc_return;
	} else {
		if (desc->dtargd_ndx + 1 > f.ctc_argc)
			goto err;

		if (ctf_func_args(fp, fbt->fbtp_symndx, argc, argv) == CTF_ERR)
			goto err;

		type = argv[desc->dtargd_ndx];
	}

	if (ctf_type_name(fp, type, desc->dtargd_native,
	    DTRACE_ARGTYPELEN) != NULL) {
		ctf_close(fp);
		return;
	}
err:
	if (fp != NULL)
		ctf_close(fp);

	desc->dtargd_ndx = DTRACE_ARGNONE;
}
/*ARGSUSED*/
static void
instr_getargdesc(void *arg, dtrace_id_t id, void *parg, dtrace_argdesc_t *desc)
{
	instr_probe_t *fbt = parg;
	struct modctl *ctl = fbt->insp_ctl;
	struct module *mp = (struct module *) ctl;
	ctf_file_t *fp = NULL;
	ctf_funcinfo_t f;
//	int error;
	ctf_id_t argv[32], type;
	int argc = sizeof (argv) / sizeof (ctf_id_t);
//	const char *parent;

	if (mp->state != MODULE_STATE_LIVE ||
	    get_refcount(mp) != fbt->insp_loadcnt)
		return;

	if (fbt->insp_roffset != 0 && desc->dtargd_ndx == 0) {
		(void) strcpy(desc->dtargd_native, "int");
		return;
	}

# if 0
	if ((fp = ctf_modopen(mp, &error)) == NULL) {
		/*
		 * We have no CTF information for this module -- and therefore
		 * no args[] information.
		 */
		goto err;
	}
# endif

	//TODO();
	if (fp == NULL)
		goto err;
# if 0

	/*
	 * If we have a parent container, we must manually import it.
	 */
	if ((parent = ctf_parent_name(fp)) != NULL) {
		ctf_file_t *pfp;
		TODO();
		struct modctl *mod;

		/*
		 * We must iterate over all modules to find the module that
		 * is our parent.
		 */
		for (mod = &modules; mod != NULL; mod = mod->mod_next) {
			if (strcmp(mod->mod_filename, parent) == 0)
				break;
		}

		if (mod == NULL)
			goto err;

		if ((pfp = ctf_modopen(mod->mod_mp, &error)) == NULL)
			goto err;

		if (ctf_import(fp, pfp) != 0) {
			ctf_close(pfp);
			goto err;
		}

		ctf_close(pfp);
	}
# endif

	if (ctf_func_info(fp, fbt->insp_symndx, &f) == CTF_ERR)
		goto err;

	if (fbt->insp_roffset != 0) {
		if (desc->dtargd_ndx > 1)
			goto err;

		ASSERT(desc->dtargd_ndx == 1);
		type = f.ctc_return;
	} else {
		if (desc->dtargd_ndx + 1 > f.ctc_argc)
			goto err;

		if (ctf_func_args(fp, fbt->insp_symndx, argc, argv) == CTF_ERR)
			goto err;

		type = argv[desc->dtargd_ndx];
	}

	if (ctf_type_name(fp, type, desc->dtargd_native,
	    DTRACE_ARGTYPELEN) != NULL) {
		ctf_close(fp);
		return;
	}
err:
	if (fp != NULL)
		ctf_close(fp);

	desc->dtargd_ndx = DTRACE_ARGNONE;
}
Example #15
0
/*
 * 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(__UNCONST(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(__UNCONST(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(__UNCONST(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(__UNCONST(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));
	}

	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));
}