Пример #1
0
static int
fbt_typoff_init(linker_ctf_t *lc)
{
	const ctf_header_t *hp = (const ctf_header_t *) lc->ctftab;
	const ctf_type_t *tbuf;
	const ctf_type_t *tend;
	const ctf_type_t *tp;
	const uint8_t *ctfdata = lc->ctftab + sizeof(ctf_header_t);
	int ctf_typemax = 0;
	uint32_t *xp;
	ulong_t pop[CTF_K_MAX + 1] = { 0 };


	/* Sanity check. */
	if (hp->cth_magic != CTF_MAGIC)
		return (EINVAL);

	tbuf = (const ctf_type_t *) (ctfdata + hp->cth_typeoff);
	tend = (const ctf_type_t *) (ctfdata + hp->cth_stroff);

	int child = hp->cth_parname != 0;

	/*
	 * 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; ctf_typemax++) {
		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
		ssize_t size, increment;

		size_t vbytes;
		uint_t n;

		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);

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

				vbytes = sizeof (ctf_lmember_t) * vlen;
				for (n = vlen; n != 0; n--, lmp++)
					child |=
					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
			}
			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)
				pop[CTF_K_STRUCT]++;
			else
				pop[tp->ctt_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);
			vbytes = 0;
			break;
		default:
			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
			return (EIO);
		}
		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
		pop[kind]++;
	}

	*lc->typlenp = ctf_typemax;

	if ((xp = malloc(sizeof(uint32_t) * ctf_typemax, M_LINKER, M_ZERO | M_WAITOK)) == NULL)
		return (ENOMEM);

	*lc->typoffp = xp;

	/* type id 0 is used as a sentinel value */
	*xp++ = 0;

	/*
	 * In the second pass, fill in the type offset.
	 */
	for (tp = tbuf; tp < tend; xp++) {
		ushort_t kind = CTF_INFO_KIND(tp->ctt_info);
		ulong_t vlen = CTF_INFO_VLEN(tp->ctt_info);
		ssize_t size, increment;

		size_t vbytes;
		uint_t n;

		(void) fbt_get_ctt_size(hp->cth_version, tp, &size, &increment);

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

				vbytes = sizeof (ctf_lmember_t) * vlen;
				for (n = vlen; n != 0; n--, lmp++)
					child |=
					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
			}
			break;
		case CTF_K_ENUM:
			vbytes = sizeof (ctf_enum_t) * vlen;
			break;
		case CTF_K_FORWARD:
		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:
			vbytes = 0;
			break;
		default:
			printf("%s(%d): detected invalid CTF kind -- %u\n", __func__, __LINE__, kind);
			return (EIO);
		}
		*xp = (uint32_t)((uintptr_t) tp - (uintptr_t) ctfdata);
		tp = (ctf_type_t *)((uintptr_t)tp + increment + vbytes);
	}

	return (0);
}
Пример #2
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);

	ulong_t pop[CTF_K_MAX + 1] = { 0 };
	const ctf_type_t *tp;
	ctf_hash_t *hp;
	ushort_t dst;
	ctf_id_t id;
	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;

		(void) ctf_get_ctt_size(fp, tp, &size, &increment);

		switch (kind) {
		case CTF_K_INTEGER:
		case CTF_K_FLOAT:
			vbytes = sizeof (uint_t);
			break;
		case CTF_K_ARRAY:
			vbytes = sizeof (ctf_array_t);
			break;
		case CTF_K_FUNCTION:
			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
			break;
		case CTF_K_STRUCT:
		case CTF_K_UNION:
			if (fp->ctf_version == CTF_VERSION_1 ||
			    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);

				vbytes = sizeof (ctf_lmember_t) * vlen;
				for (n = vlen; n != 0; n--, lmp++)
					child |=
					    CTF_TYPE_ISCHILD(lmp->ctlm_type);
			}
			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)
				pop[CTF_K_STRUCT]++;
			else
				pop[tp->ctt_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);
			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);
		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));

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

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

		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);
				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);
			}
			vbytes = sizeof (uint_t);
			break;

		case CTF_K_ARRAY:
			vbytes = sizeof (ctf_array_t);
			break;

		case CTF_K_FUNCTION:
			err = ctf_hash_insert(&fp->ctf_names, fp,
			    CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);
			if (err != 0 && err != ECTF_STRTAB)
				return (err);
			vbytes = sizeof (ushort_t) * (vlen + (vlen & 1));
			break;

		case CTF_K_STRUCT:
			err = ctf_hash_define(&fp->ctf_structs, fp,
			    CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);

			if (err != 0 && err != ECTF_STRTAB)
				return (err);

			if (fp->ctf_version == CTF_VERSION_1 ||
			    size < CTF_LSTRUCT_THRESH)
				vbytes = sizeof (ctf_member_t) * vlen;
			else {
				vbytes = sizeof (ctf_lmember_t) * vlen;
				nlstructs++;
			}
			break;

		case CTF_K_UNION:
			err = ctf_hash_define(&fp->ctf_unions, fp,
			    CTF_INDEX_TO_TYPE(id, child), tp->ctt_name);

			if (err != 0 && err != ECTF_STRTAB)
				return (err);

			if (fp->ctf_version == CTF_VERSION_1 ||
			    size < CTF_LSTRUCT_THRESH)
				vbytes = sizeof (ctf_member_t) * vlen;
			else {
				vbytes = sizeof (ctf_lmember_t) * vlen;
				nlunions++;
			}
			break;

		case CTF_K_ENUM:
			err = ctf_hash_define(&fp->ctf_enums, fp,
			    CTF_INDEX_TO_TYPE(id, child), tp->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);
			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) {
			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);
				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)
				fp->ctf_ptrtab[
				    CTF_TYPE_TO_INDEX(tp->ctt_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);
			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);
	}

	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) {
			tp = LCTF_INDEX_TO_TYPEPTR(fp, id);

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

	return (0);
}
Пример #3
0
int
main(int argc, char **argv)
{
	tdata_t *mstrtd, *savetd;
	char *uniqfile = NULL, *uniqlabel = NULL;
	char *withfile = NULL;
	char *label = NULL;
	char **ifiles, **tifiles;
	int verbose = 0, docopy = 0;
	int write_fuzzy_match = 0;
	int require_ctf = 0;
	int nifiles, nielems;
	int c, i, idx, tidx, err;

	progname = basename(argv[0]);

	if (getenv("CTFMERGE_DEBUG_LEVEL"))
		debug_level = atoi(getenv("CTFMERGE_DEBUG_LEVEL"));

	err = 0;
	while ((c = getopt(argc, argv, ":cd:D:fl:L:o:tvw:s")) != EOF) {
		switch (c) {
		case 'c':
			docopy = 1;
			break;
		case 'd':
			/* Uniquify against `uniqfile' */
			uniqfile = optarg;
			break;
		case 'D':
			/* Uniquify against label `uniqlabel' in `uniqfile' */
			uniqlabel = optarg;
			break;
		case 'f':
			write_fuzzy_match = CTF_FUZZY_MATCH;
			break;
		case 'l':
			/* Label merged types with `label' */
			label = optarg;
			break;
		case 'L':
			/* Label merged types with getenv(`label`) */
			if ((label = getenv(optarg)) == NULL)
				label = CTF_DEFAULT_LABEL;
			break;
		case 'o':
			/* Place merged types in CTF section in `outfile' */
			outfile = optarg;
			break;
		case 't':
			/* Insist *all* object files built from C have CTF */
			require_ctf = 1;
			break;
		case 'v':
			/* More debugging information */
			verbose = 1;
			break;
		case 'w':
			/* Additive merge with data from `withfile' */
			withfile = optarg;
			break;
		case 's':
			/* use the dynsym rather than the symtab */
			dynsym = CTF_USE_DYNSYM;
			break;
		default:
			usage();
			exit(2);
		}
	}

	/* Validate arguments */
	if (docopy) {
		if (uniqfile != NULL || uniqlabel != NULL || label != NULL ||
		    outfile != NULL || withfile != NULL || dynsym != 0)
			err++;

		if (argc - optind != 2)
			err++;
	} else {
		if (uniqfile != NULL && withfile != NULL)
			err++;

		if (uniqlabel != NULL && uniqfile == NULL)
			err++;

		if (outfile == NULL || label == NULL)
			err++;

		if (argc - optind == 0)
			err++;
	}

	if (err) {
		usage();
		exit(2);
	}

	if (uniqfile && access(uniqfile, R_OK) != 0) {
		warning("Uniquification file %s couldn't be opened and "
		    "will be ignored.\n", uniqfile);
		uniqfile = NULL;
	}
	if (withfile && access(withfile, R_OK) != 0) {
		warning("With file %s couldn't be opened and will be "
		    "ignored.\n", withfile);
		withfile = NULL;
	}
	if (outfile && access(outfile, R_OK|W_OK) != 0)
		terminate("Cannot open output file %s for r/w", outfile);

	/*
	 * This is ugly, but we don't want to have to have a separate tool
	 * (yet) just for copying an ELF section with our specific requirements,
	 * so we shoe-horn a copier into ctfmerge.
	 */
	if (docopy) {
		copy_ctf_data(argv[optind], argv[optind + 1]);

		exit(0);
	}

	set_terminate_cleanup(terminate_cleanup);

	/* Sort the input files and strip out duplicates */
	nifiles = argc - optind;
	ifiles = xmalloc(sizeof (char *) * nifiles);
	tifiles = xmalloc(sizeof (char *) * nifiles);

	for (i = 0; i < nifiles; i++)
		tifiles[i] = argv[optind + i];
	qsort(tifiles, nifiles, sizeof (char *), (int (*)())strcompare);

	ifiles[0] = tifiles[0];
	for (idx = 0, tidx = 1; tidx < nifiles; tidx++) {
		if (strcmp(ifiles[idx], tifiles[tidx]) != 0)
			ifiles[++idx] = tifiles[tidx];
	}
	nifiles = idx + 1;

	/* Make sure they all exist */
	if ((nielems = count_files(ifiles, nifiles)) < 0)
		terminate("Some input files were inaccessible\n");

	/* Prepare for the merge */
	wq_init(&wq, nielems);

	start_threads(&wq);

	/*
	 * Start the merge
	 *
	 * We're reading everything from each of the object files, so we
	 * don't need to specify labels.
	 */
	if (read_ctf(ifiles, nifiles, NULL, merge_ctf_cb,
	    &wq, require_ctf) == 0) {
		/*
		 * If we're verifying that C files have CTF, it's safe to
		 * assume that in this case, we're building only from assembly
		 * inputs.
		 */
		if (require_ctf)
			exit(0);
		terminate("No ctf sections found to merge\n");
	}

	pthread_mutex_lock(&wq.wq_queue_lock);
	wq.wq_nomorefiles = 1;
	pthread_cond_broadcast(&wq.wq_work_avail);
	pthread_mutex_unlock(&wq.wq_queue_lock);

	pthread_mutex_lock(&wq.wq_queue_lock);
	while (wq.wq_alldone == 0)
		pthread_cond_wait(&wq.wq_alldone_cv, &wq.wq_queue_lock);
	pthread_mutex_unlock(&wq.wq_queue_lock);

	join_threads(&wq);

	/*
	 * All requested files have been merged, with the resulting tree in
	 * mstrtd.  savetd is the tree that will be placed into the output file.
	 *
	 * Regardless of whether we're doing a normal uniquification or an
	 * additive merge, we need a type tree that has been uniquified
	 * against uniqfile or withfile, as appropriate.
	 *
	 * If we're doing a uniquification, we stuff the resulting tree into
	 * outfile.  Otherwise, we add the tree to the tree already in withfile.
	 */
	assert(fifo_len(wq.wq_queue) == 1);
	mstrtd = fifo_remove(wq.wq_queue);

	if (verbose || debug_level) {
		debug(2, "Statistics for td %p\n", (void *)mstrtd);

		iidesc_stats(mstrtd->td_iihash);
	}

	if (uniqfile != NULL || withfile != NULL) {
		char *reffile, *reflabel = NULL;
		tdata_t *reftd;

		if (uniqfile != NULL) {
			reffile = uniqfile;
			reflabel = uniqlabel;
		} else
			reffile = withfile;

		if (read_ctf(&reffile, 1, reflabel, read_ctf_save_cb,
		    &reftd, require_ctf) == 0) {
			terminate("No CTF data found in reference file %s\n",
			    reffile);
		}

		savetd = tdata_new();

		if (CTF_TYPE_ISCHILD(reftd->td_nextid))
			terminate("No room for additional types in master\n");

		savetd->td_nextid = withfile ? reftd->td_nextid :
		    CTF_INDEX_TO_TYPE(1, TRUE);
		merge_into_master(mstrtd, reftd, savetd, 0);

		tdata_label_add(savetd, label, CTF_LABEL_LASTIDX);

		if (withfile) {
			/*
			 * savetd holds the new data to be added to the withfile
			 */
			tdata_t *withtd = reftd;

			tdata_merge(withtd, savetd);

			savetd = withtd;
		} else {
			char uniqname[MAXPATHLEN];
			labelent_t *parle;

			parle = tdata_label_top(reftd);

			savetd->td_parlabel = xstrdup(parle->le_name);

			strncpy(uniqname, reffile, sizeof (uniqname));
			uniqname[MAXPATHLEN - 1] = '\0';
			savetd->td_parname = xstrdup(basename(uniqname));
		}

	} else {
		/*
		 * No post processing.  Write the merged tree as-is into the
		 * output file.
		 */
		tdata_label_free(mstrtd);
		tdata_label_add(mstrtd, label, CTF_LABEL_LASTIDX);

		savetd = mstrtd;
	}

	tmpname = mktmpname(outfile, ".ctf");
	write_ctf(savetd, outfile, tmpname,
	    CTF_COMPRESS | write_fuzzy_match | dynsym);
	if (rename(tmpname, outfile) != 0)
		terminate("Couldn't rename output temp file %s", tmpname);
	free(tmpname);

	return (0);
}