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