xref: /titanic_51/usr/src/tools/ctf/cvt/output.c (revision 68b2bbf26c7040fea4281dcb58b81e7627e46f34)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Routines for preparing tdata trees for conversion into CTF data, and
28  * for placing the resulting data into an output file.
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <strings.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <fcntl.h>
37 #include <libelf.h>
38 #include <gelf.h>
39 #include <unistd.h>
40 
41 #include "ctftools.h"
42 #include "list.h"
43 #include "memory.h"
44 #include "traverse.h"
45 #include "symbol.h"
46 
47 typedef struct iidesc_match {
48 	int iim_fuzzy;
49 	iidesc_t *iim_ret;
50 	char *iim_name;
51 	char *iim_file;
52 	uchar_t iim_bind;
53 } iidesc_match_t;
54 
55 static int
56 burst_iitypes(void *data, void *arg)
57 {
58 	iidesc_t *ii = data;
59 	iiburst_t *iiburst = arg;
60 
61 	switch (ii->ii_type) {
62 	case II_GFUN:
63 	case II_SFUN:
64 	case II_GVAR:
65 	case II_SVAR:
66 		if (!(ii->ii_flags & IIDESC_F_USED))
67 			return (0);
68 		break;
69 	default:
70 		break;
71 	}
72 
73 	ii->ii_dtype->t_flags |= TDESC_F_ISROOT;
74 	(void) iitraverse_td(ii, iiburst->iib_tdtd);
75 	return (1);
76 }
77 
78 /*ARGSUSED1*/
79 static int
80 save_type_by_id(tdesc_t *tdp, tdesc_t **tdpp, void *private)
81 {
82 	iiburst_t *iiburst = private;
83 
84 	/*
85 	 * Doing this on every node is horribly inefficient, but given that
86 	 * we may be suppressing some types, we can't trust nextid in the
87 	 * tdata_t.
88 	 */
89 	if (tdp->t_id > iiburst->iib_maxtypeid)
90 		iiburst->iib_maxtypeid = tdp->t_id;
91 
92 	slist_add(&iiburst->iib_types, tdp, tdesc_idcmp);
93 
94 	return (1);
95 }
96 
97 static tdtrav_cb_f burst_types_cbs[] = {
98 	NULL,
99 	save_type_by_id,	/* intrinsic */
100 	save_type_by_id,	/* pointer */
101 	save_type_by_id,	/* array */
102 	save_type_by_id,	/* function */
103 	save_type_by_id,	/* struct */
104 	save_type_by_id,	/* union */
105 	save_type_by_id,	/* enum */
106 	save_type_by_id,	/* forward */
107 	save_type_by_id,	/* typedef */
108 	tdtrav_assert,		/* typedef_unres */
109 	save_type_by_id,	/* volatile */
110 	save_type_by_id,	/* const */
111 	save_type_by_id		/* restrict */
112 };
113 
114 
115 static iiburst_t *
116 iiburst_new(tdata_t *td, int max)
117 {
118 	iiburst_t *iiburst = xcalloc(sizeof (iiburst_t));
119 	iiburst->iib_td = td;
120 	iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max);
121 	iiburst->iib_nfuncs = 0;
122 	iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max);
123 	iiburst->iib_nobjts = 0;
124 	return (iiburst);
125 }
126 
127 static void
128 iiburst_types(iiburst_t *iiburst)
129 {
130 	tdtrav_data_t tdtd;
131 
132 	tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs,
133 	    NULL, (void *)iiburst);
134 
135 	iiburst->iib_tdtd = &tdtd;
136 
137 	(void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst);
138 }
139 
140 static void
141 iiburst_free(iiburst_t *iiburst)
142 {
143 	free(iiburst->iib_funcs);
144 	free(iiburst->iib_objts);
145 	list_free(iiburst->iib_types, NULL, NULL);
146 	free(iiburst);
147 }
148 
149 /*
150  * See if this iidesc matches the ELF symbol data we pass in.
151  *
152  * A fuzzy match is where we have a local symbol matching the name of a
153  * global type description. This is common when a mapfile is used for a
154  * DSO, but we don't accept it by default.
155  *
156  * A weak fuzzy match is when a weak symbol was resolved and matched to
157  * a global type description.
158  */
159 static int
160 matching_iidesc(iidesc_t *iidesc, iidesc_match_t *match)
161 {
162 	if (streq(iidesc->ii_name, match->iim_name) == 0)
163 		return (0);
164 
165 	switch (iidesc->ii_type) {
166 	case II_GFUN:
167 	case II_GVAR:
168 		if (match->iim_bind == STB_GLOBAL) {
169 			match->iim_ret = iidesc;
170 			return (-1);
171 		} else if (match->iim_fuzzy && match->iim_ret == NULL) {
172 			match->iim_ret = iidesc;
173 			/* continue to look for strong match */
174 			return (0);
175 		}
176 		break;
177 	case II_SFUN:
178 	case II_SVAR:
179 		if (match->iim_bind == STB_LOCAL &&
180 		    match->iim_file != NULL &&
181 		    streq(iidesc->ii_owner, match->iim_file)) {
182 			match->iim_ret = iidesc;
183 			return (-1);
184 		}
185 		break;
186 	}
187 	return (0);
188 }
189 
190 static iidesc_t *
191 find_iidesc(tdata_t *td, iidesc_match_t *match)
192 {
193 	match->iim_ret = NULL;
194 	iter_iidescs_by_name(td, match->iim_name,
195 	    (int (*)())matching_iidesc, match);
196 	return (match->iim_ret);
197 }
198 
199 /*
200  * If we have a weak symbol, attempt to find the strong symbol it will
201  * resolve to.  Note: the code where this actually happens is in
202  * sym_process() in cmd/sgs/libld/common/syms.c
203  *
204  * Finding the matching symbol is unfortunately not trivial.  For a
205  * symbol to be a candidate, it must:
206  *
207  * - have the same type (function, object)
208  * - have the same value (address)
209  * - have the same size
210  * - not be another weak symbol
211  * - belong to the same section (checked via section index)
212  *
213  * If such a candidate is global, then we assume we've found it.  The
214  * linker generates the symbol table such that the curfile might be
215  * incorrect; this is OK for global symbols, since find_iidesc() doesn't
216  * need to check for the source file for the symbol.
217  *
218  * We might have found a strong local symbol, where the curfile is
219  * accurate and matches that of the weak symbol.  We assume this is a
220  * reasonable match.
221  *
222  * If we've got a local symbol with a non-matching curfile, there are
223  * two possibilities.  Either this is a completely different symbol, or
224  * it's a once-global symbol that was scoped to local via a mapfile.  In
225  * the latter case, curfile is likely inaccurate since the linker does
226  * not preserve the needed curfile in the order of the symbol table (see
227  * the comments about locally scoped symbols in libld's update_osym()).
228  * As we can't tell this case from the former one, we use this symbol
229  * iff no other matching symbol is found.
230  *
231  * What we really need here is a SUNW section containing weak<->strong
232  * mappings that we can consume.
233  */
234 static int
235 check_for_weak(GElf_Sym *weak, char const *weakfile,
236     Elf_Data *data, int nent, Elf_Data *strdata,
237     GElf_Sym *retsym, char **curfilep)
238 {
239 	char *curfile = NULL;
240 	char *tmpfile;
241 	GElf_Sym tmpsym;
242 	int candidate = 0;
243 	int i;
244 
245 	if (GELF_ST_BIND(weak->st_info) != STB_WEAK)
246 		return (0);
247 
248 	for (i = 0; i < nent; i++) {
249 		GElf_Sym sym;
250 		uchar_t type;
251 
252 		if (gelf_getsym(data, i, &sym) == NULL)
253 			continue;
254 
255 		type = GELF_ST_TYPE(sym.st_info);
256 
257 		if (type == STT_FILE)
258 			curfile = (char *)strdata->d_buf + sym.st_name;
259 
260 		if (GELF_ST_TYPE(weak->st_info) != type ||
261 		    weak->st_value != sym.st_value)
262 			continue;
263 
264 		if (weak->st_size != sym.st_size)
265 			continue;
266 
267 		if (GELF_ST_BIND(sym.st_info) == STB_WEAK)
268 			continue;
269 
270 		if (sym.st_shndx != weak->st_shndx)
271 			continue;
272 
273 		if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
274 		    (curfile == NULL || weakfile == NULL ||
275 		    strcmp(curfile, weakfile) != 0)) {
276 			candidate = 1;
277 			tmpfile = curfile;
278 			tmpsym = sym;
279 			continue;
280 		}
281 
282 		*curfilep = curfile;
283 		*retsym = sym;
284 		return (1);
285 	}
286 
287 	if (candidate) {
288 		*curfilep = tmpfile;
289 		*retsym = tmpsym;
290 		return (1);
291 	}
292 
293 	return (0);
294 }
295 
296 /*
297  * When we've found the underlying symbol's type description
298  * for a weak symbol, we need to copy it and rename it to match
299  * the weak symbol. We also need to add it to the td so it's
300  * handled along with the others later.
301  */
302 static iidesc_t *
303 copy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc,
304     const char *weakname, const char *weakfile)
305 {
306 	iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile);
307 	uchar_t type = GELF_ST_TYPE(sym->st_info);
308 
309 	switch (type) {
310 	case STT_OBJECT:
311 		new->ii_type = II_GVAR;
312 		break;
313 	case STT_FUNC:
314 		new->ii_type = II_GFUN;
315 		break;
316 	}
317 
318 	hash_add(td->td_iihash, new);
319 
320 	return (new);
321 }
322 
323 /*
324  * Process the symbol table of the output file, associating each symbol
325  * with a type description if possible, and sorting them into functions
326  * and data, maintaining symbol table order.
327  */
328 static iiburst_t *
329 sort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
330     int dynsym)
331 {
332 	iiburst_t *iiburst;
333 	Elf_Scn *scn;
334 	GElf_Shdr shdr;
335 	Elf_Data *data, *strdata;
336 	int i, stidx;
337 	int nent;
338 	iidesc_match_t match;
339 
340 	match.iim_fuzzy = fuzzymatch;
341 	match.iim_file = NULL;
342 
343 	if ((stidx = findelfsecidx(elf, file,
344 	    dynsym ? ".dynsym" : ".symtab")) < 0)
345 		terminate("%s: Can't open symbol table\n", file);
346 	scn = elf_getscn(elf, stidx);
347 	data = elf_getdata(scn, NULL);
348 	gelf_getshdr(scn, &shdr);
349 	nent = shdr.sh_size / shdr.sh_entsize;
350 
351 	scn = elf_getscn(elf, shdr.sh_link);
352 	strdata = elf_getdata(scn, NULL);
353 
354 	iiburst = iiburst_new(td, nent);
355 
356 	for (i = 0; i < nent; i++) {
357 		GElf_Sym sym;
358 		iidesc_t **tolist;
359 		GElf_Sym ssym;
360 		iidesc_match_t smatch;
361 		int *curr;
362 		iidesc_t *iidesc;
363 
364 		if (gelf_getsym(data, i, &sym) == NULL)
365 			elfterminate(file, "Couldn't read symbol %d", i);
366 
367 		match.iim_name = (char *)strdata->d_buf + sym.st_name;
368 		match.iim_bind = GELF_ST_BIND(sym.st_info);
369 
370 		switch (GELF_ST_TYPE(sym.st_info)) {
371 		case STT_FILE:
372 			match.iim_file = match.iim_name;
373 			continue;
374 		case STT_OBJECT:
375 			tolist = iiburst->iib_objts;
376 			curr = &iiburst->iib_nobjts;
377 			break;
378 		case STT_FUNC:
379 			tolist = iiburst->iib_funcs;
380 			curr = &iiburst->iib_nfuncs;
381 			break;
382 		default:
383 			continue;
384 		}
385 
386 		if (ignore_symbol(&sym, match.iim_name))
387 			continue;
388 
389 		iidesc = find_iidesc(td, &match);
390 
391 		if (iidesc != NULL) {
392 			tolist[*curr] = iidesc;
393 			iidesc->ii_flags |= IIDESC_F_USED;
394 			(*curr)++;
395 			continue;
396 		}
397 
398 		if (!check_for_weak(&sym, match.iim_file, data, nent, strdata,
399 		    &ssym, &smatch.iim_file)) {
400 			(*curr)++;
401 			continue;
402 		}
403 
404 		smatch.iim_fuzzy = fuzzymatch;
405 		smatch.iim_name = (char *)strdata->d_buf + ssym.st_name;
406 		smatch.iim_bind = GELF_ST_BIND(ssym.st_info);
407 
408 		debug(3, "Weak symbol %s resolved to %s\n", match.iim_name,
409 		    smatch.iim_name);
410 
411 		iidesc = find_iidesc(td, &smatch);
412 
413 		if (iidesc != NULL) {
414 			tolist[*curr] = copy_from_strong(td, &sym,
415 			    iidesc, match.iim_name, match.iim_file);
416 			tolist[*curr]->ii_flags |= IIDESC_F_USED;
417 		}
418 
419 		(*curr)++;
420 	}
421 
422 	/*
423 	 * Stabs are generated for every function declared in a given C source
424 	 * file.  When converting an object file, we may encounter a stab that
425 	 * has no symbol table entry because the optimizer has decided to omit
426 	 * that item (for example, an unreferenced static function).  We may
427 	 * see iidescs that do not have an associated symtab entry, and so
428 	 * we do not write records for those functions into the CTF data.
429 	 * All others get marked as a root by this function.
430 	 */
431 	iiburst_types(iiburst);
432 
433 	/*
434 	 * By not adding some of the functions and/or objects, we may have
435 	 * caused some types that were referenced solely by those
436 	 * functions/objects to be suppressed.  This could cause a label,
437 	 * generated prior to the evisceration, to be incorrect.  Find the
438 	 * highest type index, and change the label indicies to be no higher
439 	 * than this value.
440 	 */
441 	tdata_label_newmax(td, iiburst->iib_maxtypeid);
442 
443 	return (iiburst);
444 }
445 
446 static void
447 write_file(Elf *src, const char *srcname, Elf *dst, const char *dstname,
448     caddr_t ctfdata, size_t ctfsize, int flags)
449 {
450 	GElf_Ehdr sehdr, dehdr;
451 	Elf_Scn *sscn, *dscn;
452 	Elf_Data *sdata, *ddata;
453 	GElf_Shdr shdr;
454 	GElf_Word symtab_type;
455 	int symtab_idx = -1;
456 	off_t new_offset = 0;
457 	off_t ctfnameoff = 0;
458 	int dynsym = (flags & CTF_USE_DYNSYM);
459 	int *secxlate;
460 	int srcidx, dstidx;
461 	int curnmoff = 0;
462 	int changing = 0;
463 	int pad;
464 	int i;
465 
466 	if (gelf_newehdr(dst, gelf_getclass(src)) == 0)
467 		elfterminate(dstname, "Cannot copy ehdr to temp file");
468 	gelf_getehdr(src, &sehdr);
469 	memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
470 	gelf_update_ehdr(dst, &dehdr);
471 
472 	symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
473 
474 	/*
475 	 * Neither the existing stab sections nor the SUNW_ctf sections (new or
476 	 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
477 	 * program headers.  As such, we can just blindly copy the program
478 	 * headers from the existing file to the new file.
479 	 */
480 	if (sehdr.e_phnum != 0) {
481 		(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
482 		if (gelf_newphdr(dst, sehdr.e_phnum) == 0)
483 			elfterminate(dstname, "Cannot make phdrs in temp file");
484 
485 		for (i = 0; i < sehdr.e_phnum; i++) {
486 			GElf_Phdr phdr;
487 
488 			gelf_getphdr(src, i, &phdr);
489 			gelf_update_phdr(dst, i, &phdr);
490 		}
491 	}
492 
493 	secxlate = xmalloc(sizeof (int) * sehdr.e_shnum);
494 	for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) {
495 		Elf_Scn *scn = elf_getscn(src, srcidx);
496 		GElf_Shdr shdr;
497 		char *sname;
498 
499 		gelf_getshdr(scn, &shdr);
500 		sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
501 		if (sname == NULL) {
502 			elfterminate(srcname, "Can't find string at %u",
503 			    shdr.sh_name);
504 		}
505 
506 		if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
507 			secxlate[srcidx] = -1;
508 		} else if (dynsym && shdr.sh_type == SHT_SYMTAB) {
509 			/*
510 			 * If we're building CTF against the dynsym,
511 			 * we'll rip out the symtab so debuggers aren't
512 			 * confused.
513 			 */
514 			secxlate[srcidx] = -1;
515 		} else {
516 			secxlate[srcidx] = dstidx++;
517 			curnmoff += strlen(sname) + 1;
518 		}
519 
520 		new_offset = (off_t)dehdr.e_phoff;
521 	}
522 
523 	for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) {
524 		char *sname;
525 
526 		sscn = elf_getscn(src, srcidx);
527 		gelf_getshdr(sscn, &shdr);
528 
529 		if (secxlate[srcidx] == -1) {
530 			changing = 1;
531 			continue;
532 		}
533 
534 		dscn = elf_newscn(dst);
535 
536 		/*
537 		 * If this file has program headers, we need to explicitly lay
538 		 * out sections.  If none of the sections prior to this one have
539 		 * been removed, then we can just use the existing location.  If
540 		 * one or more sections have been changed, then we need to
541 		 * adjust this one to avoid holes.
542 		 */
543 		if (changing && sehdr.e_phnum != 0) {
544 			pad = new_offset % shdr.sh_addralign;
545 
546 			if (pad)
547 				new_offset += shdr.sh_addralign - pad;
548 			shdr.sh_offset = new_offset;
549 		}
550 
551 		shdr.sh_link = secxlate[shdr.sh_link];
552 
553 		if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
554 			shdr.sh_info = secxlate[shdr.sh_info];
555 
556 		sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
557 		if (sname == NULL) {
558 			elfterminate(srcname, "Can't find string at %u",
559 			    shdr.sh_name);
560 		}
561 		if ((sdata = elf_getdata(sscn, NULL)) == NULL)
562 			elfterminate(srcname, "Cannot get sect %s data", sname);
563 		if ((ddata = elf_newdata(dscn)) == NULL)
564 			elfterminate(dstname, "Can't make sect %s data", sname);
565 		bcopy(sdata, ddata, sizeof (Elf_Data));
566 
567 		if (srcidx == sehdr.e_shstrndx) {
568 			char seclen = strlen(CTF_ELF_SCN_NAME);
569 
570 			ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size +
571 			    seclen + 1);
572 			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
573 			strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
574 			    CTF_ELF_SCN_NAME);
575 			ctfnameoff = (off_t)shdr.sh_size;
576 			shdr.sh_size += seclen + 1;
577 			ddata->d_size += seclen + 1;
578 
579 			if (sehdr.e_phnum != 0)
580 				changing = 1;
581 		}
582 
583 		if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) {
584 			int nsym = shdr.sh_size / shdr.sh_entsize;
585 
586 			symtab_idx = secxlate[srcidx];
587 
588 			ddata->d_buf = xmalloc(shdr.sh_size);
589 			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
590 
591 			for (i = 0; i < nsym; i++) {
592 				GElf_Sym sym;
593 				short newscn;
594 
595 				(void) gelf_getsym(ddata, i, &sym);
596 
597 				if (sym.st_shndx >= SHN_LORESERVE)
598 					continue;
599 
600 				if ((newscn = secxlate[sym.st_shndx]) !=
601 				    sym.st_shndx) {
602 					sym.st_shndx =
603 					    (newscn == -1 ? 1 : newscn);
604 
605 					gelf_update_sym(ddata, i, &sym);
606 				}
607 			}
608 		}
609 
610 		if (gelf_update_shdr(dscn, &shdr) == 0)
611 			elfterminate(dstname, "Cannot update sect %s", sname);
612 
613 		new_offset = (off_t)shdr.sh_offset;
614 		if (shdr.sh_type != SHT_NOBITS)
615 			new_offset += shdr.sh_size;
616 	}
617 
618 	if (symtab_idx == -1) {
619 		terminate("%s: Cannot find %s section\n", srcname,
620 		    dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB");
621 	}
622 
623 	/* Add the ctf section */
624 	dscn = elf_newscn(dst);
625 	gelf_getshdr(dscn, &shdr);
626 	shdr.sh_name = ctfnameoff;
627 	shdr.sh_type = SHT_PROGBITS;
628 	shdr.sh_size = ctfsize;
629 	shdr.sh_link = symtab_idx;
630 	shdr.sh_addralign = 4;
631 	if (changing && sehdr.e_phnum != 0) {
632 		pad = new_offset % shdr.sh_addralign;
633 
634 		if (pad)
635 			new_offset += shdr.sh_addralign - pad;
636 
637 		shdr.sh_offset = new_offset;
638 		new_offset += shdr.sh_size;
639 	}
640 
641 	ddata = elf_newdata(dscn);
642 	ddata->d_buf = ctfdata;
643 	ddata->d_size = ctfsize;
644 	ddata->d_align = shdr.sh_addralign;
645 
646 	gelf_update_shdr(dscn, &shdr);
647 
648 	/* update the section header location */
649 	if (sehdr.e_phnum != 0) {
650 		size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
651 		size_t r = new_offset % align;
652 
653 		if (r)
654 			new_offset += align - r;
655 
656 		dehdr.e_shoff = new_offset;
657 	}
658 
659 	/* commit to disk */
660 	dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
661 	gelf_update_ehdr(dst, &dehdr);
662 	if (elf_update(dst, ELF_C_WRITE) < 0)
663 		elfterminate(dstname, "Cannot finalize temp file");
664 
665 	free(secxlate);
666 }
667 
668 static caddr_t
669 make_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags)
670 {
671 	iiburst_t *iiburst;
672 	caddr_t data;
673 
674 	iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH,
675 	    flags & CTF_USE_DYNSYM);
676 	data = ctf_gen(iiburst, lenp, flags & CTF_COMPRESS);
677 
678 	iiburst_free(iiburst);
679 
680 	return (data);
681 }
682 
683 void
684 write_ctf(tdata_t *td, const char *curname, const char *newname, int flags)
685 {
686 	struct stat st;
687 	Elf *elf = NULL;
688 	Elf *telf = NULL;
689 	caddr_t data;
690 	size_t len;
691 	int fd = -1;
692 	int tfd = -1;
693 
694 	(void) elf_version(EV_CURRENT);
695 	if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
696 		terminate("%s: Cannot open for re-reading", curname);
697 	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
698 		elfterminate(curname, "Cannot re-read");
699 
700 	if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
701 		terminate("Cannot open temp file %s for writing", newname);
702 	if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL)
703 		elfterminate(curname, "Cannot write");
704 
705 	data = make_ctf_data(td, elf, curname, &len, flags);
706 	write_file(elf, curname, telf, newname, data, len, flags);
707 	free(data);
708 
709 	elf_end(telf);
710 	elf_end(elf);
711 	(void) close(fd);
712 	(void) close(tfd);
713 }
714