Esempio n. 1
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);
}
Esempio n. 2
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);
}
Esempio n. 3
0
/*
 * 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;

	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.ctf, sizeof (hdr));

	if (fstat64(fd, &st) == -1)
		return (ctf_set_open_errno(errp, errno));

	if ((nbytes = pread64(fd, &hdr.ctf, 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)
			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) {
#ifdef	_BIG_ENDIAN
		uchar_t order = ELFDATA2MSB;
#else
		uchar_t order = ELFDATA2LSB;
#endif
		GElf_Half i, n;
		GElf_Shdr *sp;

		void *strs_map;
		size_t strs_mapsz;
		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);
		}

		if (hdr.e64.e_shstrndx >= hdr.e64.e_shnum)
			return (ctf_set_open_errno(errp, ECTF_CORRUPT));

		n = hdr.e64.e_shnum;
		nbytes = sizeof (GElf_Shdr) * n;

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

			if ((sp32 = malloc(nbytes)) == NULL || pread64(fd,
			    sp32, nbytes, hdr.e64.e_shoff) != nbytes) {
				free(sp);
				return (ctf_set_open_errno(errp, errno));
			}

			for (i = 0; i < n; 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[hdr.e64.e_shstrndx].sh_size +
		    (sp[hdr.e64.e_shstrndx].sh_offset & ~_PAGEMASK);

		strs_map = mmap64(NULL, strs_mapsz, PROT_READ, MAP_PRIVATE,
		    fd, sp[hdr.e64.e_shstrndx].sh_offset & _PAGEMASK);

		strs = (char *)strs_map +
		    (sp[hdr.e64.e_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 < n; i++) {
			const GElf_Shdr *shp = &sp[i];
			const GElf_Shdr *lhp = &sp[shp->sh_link];

			if (shp->sh_link >= hdr.e64.e_shnum)
				continue; /* corrupt sh_link field */

			if (shp->sh_name >= sp[hdr.e64.e_shstrndx].sh_size ||
			    lhp->sh_name >= sp[hdr.e64.e_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));
}
Esempio n. 4
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);
}
Esempio n. 5
0
/*
 * 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);
}