1178481Sjb/*
2178481Sjb * CDDL HEADER START
3178481Sjb *
4178481Sjb * The contents of this file are subject to the terms of the
5178481Sjb * Common Development and Distribution License (the "License").
6178481Sjb * You may not use this file except in compliance with the License.
7178481Sjb *
8178481Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178481Sjb * or http://www.opensolaris.org/os/licensing.
10178481Sjb * See the License for the specific language governing permissions
11178481Sjb * and limitations under the License.
12178481Sjb *
13178481Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178481Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178481Sjb * If applicable, add the following below this CDDL HEADER, with the
16178481Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178481Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178481Sjb *
19178481Sjb * CDDL HEADER END
20178481Sjb */
21178481Sjb/*
22178481Sjb * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23178481Sjb * Use is subject to license terms.
24178481Sjb */
25178481Sjb
26178481Sjb#pragma ident	"%Z%%M%	%I%	%E% SMI"
27178481Sjb
28178481Sjb/*
29178481Sjb * Routines for preparing tdata trees for conversion into CTF data, and
30178481Sjb * for placing the resulting data into an output file.
31178481Sjb */
32178481Sjb
33178481Sjb#include <stdio.h>
34178481Sjb#include <stdlib.h>
35178481Sjb#include <strings.h>
36178481Sjb#include <sys/types.h>
37178481Sjb#include <sys/stat.h>
38178481Sjb#include <fcntl.h>
39178481Sjb#include <libelf.h>
40178481Sjb#include <gelf.h>
41178481Sjb#include <unistd.h>
42178481Sjb
43178481Sjb#include "ctftools.h"
44178481Sjb#include "list.h"
45178481Sjb#include "memory.h"
46178481Sjb#include "traverse.h"
47178481Sjb#include "symbol.h"
48178481Sjb
49178481Sjbtypedef struct iidesc_match {
50178481Sjb	int iim_fuzzy;
51178481Sjb	iidesc_t *iim_ret;
52178481Sjb	char *iim_name;
53178481Sjb	char *iim_file;
54178481Sjb	uchar_t iim_bind;
55178481Sjb} iidesc_match_t;
56178481Sjb
57178481Sjbstatic int
58178481Sjbburst_iitypes(void *data, void *arg)
59178481Sjb{
60178481Sjb	iidesc_t *ii = data;
61178481Sjb	iiburst_t *iiburst = arg;
62178481Sjb
63178481Sjb	switch (ii->ii_type) {
64178481Sjb	case II_GFUN:
65178481Sjb	case II_SFUN:
66178481Sjb	case II_GVAR:
67178481Sjb	case II_SVAR:
68178481Sjb		if (!(ii->ii_flags & IIDESC_F_USED))
69178481Sjb			return (0);
70178481Sjb		break;
71178481Sjb	default:
72178481Sjb		break;
73178481Sjb	}
74178481Sjb
75178481Sjb	ii->ii_dtype->t_flags |= TDESC_F_ISROOT;
76178481Sjb	(void) iitraverse_td(ii, iiburst->iib_tdtd);
77178481Sjb	return (1);
78178481Sjb}
79178481Sjb
80178481Sjb/*ARGSUSED1*/
81178481Sjbstatic int
82178546Sjbsave_type_by_id(tdesc_t *tdp, tdesc_t **tdpp __unused, void *private)
83178481Sjb{
84178481Sjb	iiburst_t *iiburst = private;
85178481Sjb
86178481Sjb	/*
87178481Sjb	 * Doing this on every node is horribly inefficient, but given that
88178481Sjb	 * we may be suppressing some types, we can't trust nextid in the
89178481Sjb	 * tdata_t.
90178481Sjb	 */
91178481Sjb	if (tdp->t_id > iiburst->iib_maxtypeid)
92178481Sjb		iiburst->iib_maxtypeid = tdp->t_id;
93178481Sjb
94178481Sjb	slist_add(&iiburst->iib_types, tdp, tdesc_idcmp);
95178481Sjb
96178481Sjb	return (1);
97178481Sjb}
98178481Sjb
99178481Sjbstatic tdtrav_cb_f burst_types_cbs[] = {
100178481Sjb	NULL,
101178481Sjb	save_type_by_id,	/* intrinsic */
102178481Sjb	save_type_by_id,	/* pointer */
103178481Sjb	save_type_by_id,	/* array */
104178481Sjb	save_type_by_id,	/* function */
105178481Sjb	save_type_by_id,	/* struct */
106178481Sjb	save_type_by_id,	/* union */
107178481Sjb	save_type_by_id,	/* enum */
108178481Sjb	save_type_by_id,	/* forward */
109178481Sjb	save_type_by_id,	/* typedef */
110178481Sjb	tdtrav_assert,		/* typedef_unres */
111178481Sjb	save_type_by_id,	/* volatile */
112178481Sjb	save_type_by_id,	/* const */
113178481Sjb	save_type_by_id		/* restrict */
114178481Sjb};
115178481Sjb
116178481Sjb
117178481Sjbstatic iiburst_t *
118178481Sjbiiburst_new(tdata_t *td, int max)
119178481Sjb{
120178481Sjb	iiburst_t *iiburst = xcalloc(sizeof (iiburst_t));
121178481Sjb	iiburst->iib_td = td;
122178481Sjb	iiburst->iib_funcs = xcalloc(sizeof (iidesc_t *) * max);
123178481Sjb	iiburst->iib_nfuncs = 0;
124178481Sjb	iiburst->iib_objts = xcalloc(sizeof (iidesc_t *) * max);
125178481Sjb	iiburst->iib_nobjts = 0;
126178481Sjb	return (iiburst);
127178481Sjb}
128178481Sjb
129178481Sjbstatic void
130178481Sjbiiburst_types(iiburst_t *iiburst)
131178481Sjb{
132178481Sjb	tdtrav_data_t tdtd;
133178481Sjb
134178481Sjb	tdtrav_init(&tdtd, &iiburst->iib_td->td_curvgen, NULL, burst_types_cbs,
135178481Sjb	    NULL, (void *)iiburst);
136178481Sjb
137178481Sjb	iiburst->iib_tdtd = &tdtd;
138178481Sjb
139178481Sjb	(void) hash_iter(iiburst->iib_td->td_iihash, burst_iitypes, iiburst);
140178481Sjb}
141178481Sjb
142178481Sjbstatic void
143178481Sjbiiburst_free(iiburst_t *iiburst)
144178481Sjb{
145178481Sjb	free(iiburst->iib_funcs);
146178481Sjb	free(iiburst->iib_objts);
147178481Sjb	list_free(iiburst->iib_types, NULL, NULL);
148178481Sjb	free(iiburst);
149178481Sjb}
150178481Sjb
151178481Sjb/*
152178481Sjb * See if this iidesc matches the ELF symbol data we pass in.
153178481Sjb *
154178481Sjb * A fuzzy match is where we have a local symbol matching the name of a
155178481Sjb * global type description. This is common when a mapfile is used for a
156178481Sjb * DSO, but we don't accept it by default.
157178481Sjb *
158178481Sjb * A weak fuzzy match is when a weak symbol was resolved and matched to
159178481Sjb * a global type description.
160178481Sjb */
161178481Sjbstatic int
162178546Sjbmatching_iidesc(void *arg1, void *arg2)
163178481Sjb{
164178546Sjb	iidesc_t *iidesc = arg1;
165178546Sjb	iidesc_match_t *match = arg2;
166178481Sjb	if (streq(iidesc->ii_name, match->iim_name) == 0)
167178481Sjb		return (0);
168178481Sjb
169178481Sjb	switch (iidesc->ii_type) {
170178481Sjb	case II_GFUN:
171178481Sjb	case II_GVAR:
172178481Sjb		if (match->iim_bind == STB_GLOBAL) {
173178481Sjb			match->iim_ret = iidesc;
174178481Sjb			return (-1);
175178481Sjb		} else if (match->iim_fuzzy && match->iim_ret == NULL) {
176178481Sjb			match->iim_ret = iidesc;
177178481Sjb			/* continue to look for strong match */
178178481Sjb			return (0);
179178481Sjb		}
180178481Sjb		break;
181178481Sjb	case II_SFUN:
182178481Sjb	case II_SVAR:
183178481Sjb		if (match->iim_bind == STB_LOCAL &&
184178481Sjb		    match->iim_file != NULL &&
185178481Sjb		    streq(iidesc->ii_owner, match->iim_file)) {
186178481Sjb			match->iim_ret = iidesc;
187178481Sjb			return (-1);
188178481Sjb		}
189178481Sjb		break;
190178546Sjb	default:
191178546Sjb		break;
192178481Sjb	}
193178481Sjb	return (0);
194178481Sjb}
195178481Sjb
196178481Sjbstatic iidesc_t *
197178481Sjbfind_iidesc(tdata_t *td, iidesc_match_t *match)
198178481Sjb{
199178481Sjb	match->iim_ret = NULL;
200178481Sjb	iter_iidescs_by_name(td, match->iim_name,
201178546Sjb	    matching_iidesc, match);
202178481Sjb	return (match->iim_ret);
203178481Sjb}
204178481Sjb
205178481Sjb/*
206178481Sjb * If we have a weak symbol, attempt to find the strong symbol it will
207178481Sjb * resolve to.  Note: the code where this actually happens is in
208178481Sjb * sym_process() in cmd/sgs/libld/common/syms.c
209178481Sjb *
210178481Sjb * Finding the matching symbol is unfortunately not trivial.  For a
211178481Sjb * symbol to be a candidate, it must:
212178481Sjb *
213178481Sjb * - have the same type (function, object)
214178481Sjb * - have the same value (address)
215178481Sjb * - have the same size
216178481Sjb * - not be another weak symbol
217178481Sjb * - belong to the same section (checked via section index)
218178481Sjb *
219178481Sjb * If such a candidate is global, then we assume we've found it.  The
220178481Sjb * linker generates the symbol table such that the curfile might be
221178481Sjb * incorrect; this is OK for global symbols, since find_iidesc() doesn't
222178481Sjb * need to check for the source file for the symbol.
223178481Sjb *
224178481Sjb * We might have found a strong local symbol, where the curfile is
225178481Sjb * accurate and matches that of the weak symbol.  We assume this is a
226178481Sjb * reasonable match.
227178481Sjb *
228178481Sjb * If we've got a local symbol with a non-matching curfile, there are
229178481Sjb * two possibilities.  Either this is a completely different symbol, or
230178481Sjb * it's a once-global symbol that was scoped to local via a mapfile.  In
231178481Sjb * the latter case, curfile is likely inaccurate since the linker does
232178481Sjb * not preserve the needed curfile in the order of the symbol table (see
233178481Sjb * the comments about locally scoped symbols in libld's update_osym()).
234178481Sjb * As we can't tell this case from the former one, we use this symbol
235178481Sjb * iff no other matching symbol is found.
236178481Sjb *
237178481Sjb * What we really need here is a SUNW section containing weak<->strong
238178481Sjb * mappings that we can consume.
239178481Sjb */
240178481Sjbstatic int
241178481Sjbcheck_for_weak(GElf_Sym *weak, char const *weakfile,
242178481Sjb    Elf_Data *data, int nent, Elf_Data *strdata,
243178481Sjb    GElf_Sym *retsym, char **curfilep)
244178481Sjb{
245178481Sjb	char *curfile = NULL;
246178546Sjb	char *tmpfile1 = NULL;
247178481Sjb	GElf_Sym tmpsym;
248178481Sjb	int candidate = 0;
249178481Sjb	int i;
250178546Sjb	tmpsym.st_info = 0;
251178546Sjb	tmpsym.st_name = 0;
252178481Sjb
253178481Sjb	if (GELF_ST_BIND(weak->st_info) != STB_WEAK)
254178481Sjb		return (0);
255178481Sjb
256178481Sjb	for (i = 0; i < nent; i++) {
257178481Sjb		GElf_Sym sym;
258178481Sjb		uchar_t type;
259178481Sjb
260178481Sjb		if (gelf_getsym(data, i, &sym) == NULL)
261178481Sjb			continue;
262178481Sjb
263178481Sjb		type = GELF_ST_TYPE(sym.st_info);
264178481Sjb
265178481Sjb		if (type == STT_FILE)
266178481Sjb			curfile = (char *)strdata->d_buf + sym.st_name;
267178481Sjb
268178481Sjb		if (GELF_ST_TYPE(weak->st_info) != type ||
269178481Sjb		    weak->st_value != sym.st_value)
270178481Sjb			continue;
271178481Sjb
272178481Sjb		if (weak->st_size != sym.st_size)
273178481Sjb			continue;
274178481Sjb
275178481Sjb		if (GELF_ST_BIND(sym.st_info) == STB_WEAK)
276178481Sjb			continue;
277178481Sjb
278178481Sjb		if (sym.st_shndx != weak->st_shndx)
279178481Sjb			continue;
280178481Sjb
281178481Sjb		if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
282178481Sjb		    (curfile == NULL || weakfile == NULL ||
283178481Sjb		    strcmp(curfile, weakfile) != 0)) {
284178481Sjb			candidate = 1;
285178546Sjb			tmpfile1 = curfile;
286178481Sjb			tmpsym = sym;
287178481Sjb			continue;
288178481Sjb		}
289178481Sjb
290178481Sjb		*curfilep = curfile;
291178481Sjb		*retsym = sym;
292178481Sjb		return (1);
293178481Sjb	}
294178481Sjb
295178481Sjb	if (candidate) {
296178546Sjb		*curfilep = tmpfile1;
297178481Sjb		*retsym = tmpsym;
298178481Sjb		return (1);
299178481Sjb	}
300178481Sjb
301178481Sjb	return (0);
302178481Sjb}
303178481Sjb
304178481Sjb/*
305178481Sjb * When we've found the underlying symbol's type description
306178481Sjb * for a weak symbol, we need to copy it and rename it to match
307178481Sjb * the weak symbol. We also need to add it to the td so it's
308178481Sjb * handled along with the others later.
309178481Sjb */
310178481Sjbstatic iidesc_t *
311178481Sjbcopy_from_strong(tdata_t *td, GElf_Sym *sym, iidesc_t *strongdesc,
312178481Sjb    const char *weakname, const char *weakfile)
313178481Sjb{
314178481Sjb	iidesc_t *new = iidesc_dup_rename(strongdesc, weakname, weakfile);
315178481Sjb	uchar_t type = GELF_ST_TYPE(sym->st_info);
316178481Sjb
317178481Sjb	switch (type) {
318178481Sjb	case STT_OBJECT:
319178481Sjb		new->ii_type = II_GVAR;
320178481Sjb		break;
321178481Sjb	case STT_FUNC:
322178481Sjb		new->ii_type = II_GFUN;
323178481Sjb		break;
324178481Sjb	}
325178481Sjb
326178481Sjb	hash_add(td->td_iihash, new);
327178481Sjb
328178481Sjb	return (new);
329178481Sjb}
330178481Sjb
331178481Sjb/*
332178481Sjb * Process the symbol table of the output file, associating each symbol
333178481Sjb * with a type description if possible, and sorting them into functions
334178481Sjb * and data, maintaining symbol table order.
335178481Sjb */
336178481Sjbstatic iiburst_t *
337178481Sjbsort_iidescs(Elf *elf, const char *file, tdata_t *td, int fuzzymatch,
338178481Sjb    int dynsym)
339178481Sjb{
340178481Sjb	iiburst_t *iiburst;
341178481Sjb	Elf_Scn *scn;
342178481Sjb	GElf_Shdr shdr;
343178481Sjb	Elf_Data *data, *strdata;
344178481Sjb	int i, stidx;
345178481Sjb	int nent;
346178481Sjb	iidesc_match_t match;
347178481Sjb
348178481Sjb	match.iim_fuzzy = fuzzymatch;
349178481Sjb	match.iim_file = NULL;
350178481Sjb
351178481Sjb	if ((stidx = findelfsecidx(elf, file,
352178481Sjb	    dynsym ? ".dynsym" : ".symtab")) < 0)
353178481Sjb		terminate("%s: Can't open symbol table\n", file);
354178481Sjb	scn = elf_getscn(elf, stidx);
355178481Sjb	data = elf_getdata(scn, NULL);
356178481Sjb	gelf_getshdr(scn, &shdr);
357178481Sjb	nent = shdr.sh_size / shdr.sh_entsize;
358178481Sjb
359178481Sjb	scn = elf_getscn(elf, shdr.sh_link);
360178481Sjb	strdata = elf_getdata(scn, NULL);
361178481Sjb
362178481Sjb	iiburst = iiburst_new(td, nent);
363178481Sjb
364178481Sjb	for (i = 0; i < nent; i++) {
365178481Sjb		GElf_Sym sym;
366247960Sdim		char *bname;
367178481Sjb		iidesc_t **tolist;
368178481Sjb		GElf_Sym ssym;
369178481Sjb		iidesc_match_t smatch;
370178481Sjb		int *curr;
371178481Sjb		iidesc_t *iidesc;
372178481Sjb
373178481Sjb		if (gelf_getsym(data, i, &sym) == NULL)
374178481Sjb			elfterminate(file, "Couldn't read symbol %d", i);
375178481Sjb
376178481Sjb		match.iim_name = (char *)strdata->d_buf + sym.st_name;
377178481Sjb		match.iim_bind = GELF_ST_BIND(sym.st_info);
378178481Sjb
379178481Sjb		switch (GELF_ST_TYPE(sym.st_info)) {
380178481Sjb		case STT_FILE:
381247960Sdim			bname = strrchr(match.iim_name, '/');
382247962Sdim			match.iim_file = bname == NULL ? match.iim_name : bname + 1;
383178481Sjb			continue;
384178481Sjb		case STT_OBJECT:
385178481Sjb			tolist = iiburst->iib_objts;
386178481Sjb			curr = &iiburst->iib_nobjts;
387178481Sjb			break;
388178481Sjb		case STT_FUNC:
389178481Sjb			tolist = iiburst->iib_funcs;
390178481Sjb			curr = &iiburst->iib_nfuncs;
391178481Sjb			break;
392178481Sjb		default:
393178481Sjb			continue;
394178481Sjb		}
395178481Sjb
396178481Sjb		if (ignore_symbol(&sym, match.iim_name))
397178481Sjb			continue;
398178481Sjb
399178481Sjb		iidesc = find_iidesc(td, &match);
400178481Sjb
401178481Sjb		if (iidesc != NULL) {
402178481Sjb			tolist[*curr] = iidesc;
403178481Sjb			iidesc->ii_flags |= IIDESC_F_USED;
404178481Sjb			(*curr)++;
405178481Sjb			continue;
406178481Sjb		}
407178481Sjb
408178481Sjb		if (!check_for_weak(&sym, match.iim_file, data, nent, strdata,
409178481Sjb		    &ssym, &smatch.iim_file)) {
410178481Sjb			(*curr)++;
411178481Sjb			continue;
412178481Sjb		}
413178481Sjb
414178481Sjb		smatch.iim_fuzzy = fuzzymatch;
415178481Sjb		smatch.iim_name = (char *)strdata->d_buf + ssym.st_name;
416178481Sjb		smatch.iim_bind = GELF_ST_BIND(ssym.st_info);
417178481Sjb
418178481Sjb		debug(3, "Weak symbol %s resolved to %s\n", match.iim_name,
419178481Sjb		    smatch.iim_name);
420178481Sjb
421178481Sjb		iidesc = find_iidesc(td, &smatch);
422178481Sjb
423178481Sjb		if (iidesc != NULL) {
424178481Sjb			tolist[*curr] = copy_from_strong(td, &sym,
425178481Sjb			    iidesc, match.iim_name, match.iim_file);
426178481Sjb			tolist[*curr]->ii_flags |= IIDESC_F_USED;
427178481Sjb		}
428178481Sjb
429178481Sjb		(*curr)++;
430178481Sjb	}
431178481Sjb
432178481Sjb	/*
433178481Sjb	 * Stabs are generated for every function declared in a given C source
434178481Sjb	 * file.  When converting an object file, we may encounter a stab that
435178481Sjb	 * has no symbol table entry because the optimizer has decided to omit
436178481Sjb	 * that item (for example, an unreferenced static function).  We may
437178481Sjb	 * see iidescs that do not have an associated symtab entry, and so
438178481Sjb	 * we do not write records for those functions into the CTF data.
439178481Sjb	 * All others get marked as a root by this function.
440178481Sjb	 */
441178481Sjb	iiburst_types(iiburst);
442178481Sjb
443178481Sjb	/*
444178481Sjb	 * By not adding some of the functions and/or objects, we may have
445178481Sjb	 * caused some types that were referenced solely by those
446178481Sjb	 * functions/objects to be suppressed.  This could cause a label,
447178481Sjb	 * generated prior to the evisceration, to be incorrect.  Find the
448178481Sjb	 * highest type index, and change the label indicies to be no higher
449178481Sjb	 * than this value.
450178481Sjb	 */
451178481Sjb	tdata_label_newmax(td, iiburst->iib_maxtypeid);
452178481Sjb
453178481Sjb	return (iiburst);
454178481Sjb}
455178481Sjb
456178481Sjbstatic void
457178481Sjbwrite_file(Elf *src, const char *srcname, Elf *dst, const char *dstname,
458178481Sjb    caddr_t ctfdata, size_t ctfsize, int flags)
459178481Sjb{
460178481Sjb	GElf_Ehdr sehdr, dehdr;
461178481Sjb	Elf_Scn *sscn, *dscn;
462178481Sjb	Elf_Data *sdata, *ddata;
463178481Sjb	GElf_Shdr shdr;
464178481Sjb	GElf_Word symtab_type;
465178481Sjb	int symtab_idx = -1;
466178481Sjb	off_t new_offset = 0;
467178481Sjb	off_t ctfnameoff = 0;
468178481Sjb	int dynsym = (flags & CTF_USE_DYNSYM);
469178481Sjb	int keep_stabs = (flags & CTF_KEEP_STABS);
470178481Sjb	int *secxlate;
471178481Sjb	int srcidx, dstidx;
472178481Sjb	int curnmoff = 0;
473178481Sjb	int changing = 0;
474178481Sjb	int pad;
475178481Sjb	int i;
476178481Sjb
477178481Sjb	if (gelf_newehdr(dst, gelf_getclass(src)) == NULL)
478178481Sjb		elfterminate(dstname, "Cannot copy ehdr to temp file");
479178481Sjb	gelf_getehdr(src, &sehdr);
480178481Sjb	memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
481178481Sjb	gelf_update_ehdr(dst, &dehdr);
482178481Sjb
483178481Sjb	symtab_type = dynsym ? SHT_DYNSYM : SHT_SYMTAB;
484178481Sjb
485178481Sjb	/*
486178481Sjb	 * Neither the existing stab sections nor the SUNW_ctf sections (new or
487178481Sjb	 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
488178481Sjb	 * program headers.  As such, we can just blindly copy the program
489178481Sjb	 * headers from the existing file to the new file.
490178481Sjb	 */
491178481Sjb	if (sehdr.e_phnum != 0) {
492178481Sjb		(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
493178481Sjb		if (gelf_newphdr(dst, sehdr.e_phnum) == NULL)
494178481Sjb			elfterminate(dstname, "Cannot make phdrs in temp file");
495178481Sjb
496178481Sjb		for (i = 0; i < sehdr.e_phnum; i++) {
497178481Sjb			GElf_Phdr phdr;
498178481Sjb
499178481Sjb			gelf_getphdr(src, i, &phdr);
500178481Sjb			gelf_update_phdr(dst, i, &phdr);
501178481Sjb		}
502178481Sjb	}
503178481Sjb
504178481Sjb	secxlate = xmalloc(sizeof (int) * sehdr.e_shnum);
505178481Sjb	for (srcidx = dstidx = 0; srcidx < sehdr.e_shnum; srcidx++) {
506178481Sjb		Elf_Scn *scn = elf_getscn(src, srcidx);
507178546Sjb		GElf_Shdr shdr1;
508178481Sjb		char *sname;
509178481Sjb
510178546Sjb		gelf_getshdr(scn, &shdr1);
511178546Sjb		sname = elf_strptr(src, sehdr.e_shstrndx, shdr1.sh_name);
512178481Sjb		if (sname == NULL) {
513178481Sjb			elfterminate(srcname, "Can't find string at %u",
514178546Sjb			    shdr1.sh_name);
515178481Sjb		}
516178481Sjb
517178481Sjb		if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
518178481Sjb			secxlate[srcidx] = -1;
519178481Sjb		} else if (!keep_stabs &&
520178481Sjb		    (strncmp(sname, ".stab", 5) == 0 ||
521178481Sjb		    strncmp(sname, ".debug", 6) == 0 ||
522178481Sjb		    strncmp(sname, ".rel.debug", 10) == 0 ||
523178481Sjb		    strncmp(sname, ".rela.debug", 11) == 0)) {
524178481Sjb			secxlate[srcidx] = -1;
525178546Sjb		} else if (dynsym && shdr1.sh_type == SHT_SYMTAB) {
526178481Sjb			/*
527178481Sjb			 * If we're building CTF against the dynsym,
528178481Sjb			 * we'll rip out the symtab so debuggers aren't
529178481Sjb			 * confused.
530178481Sjb			 */
531178481Sjb			secxlate[srcidx] = -1;
532178481Sjb		} else {
533178481Sjb			secxlate[srcidx] = dstidx++;
534178481Sjb			curnmoff += strlen(sname) + 1;
535178481Sjb		}
536178481Sjb
537178481Sjb		new_offset = (off_t)dehdr.e_phoff;
538178481Sjb	}
539178481Sjb
540178481Sjb	for (srcidx = 1; srcidx < sehdr.e_shnum; srcidx++) {
541178481Sjb		char *sname;
542178481Sjb
543178481Sjb		sscn = elf_getscn(src, srcidx);
544178481Sjb		gelf_getshdr(sscn, &shdr);
545178481Sjb
546178481Sjb		if (secxlate[srcidx] == -1) {
547178481Sjb			changing = 1;
548178481Sjb			continue;
549178481Sjb		}
550178481Sjb
551178481Sjb		dscn = elf_newscn(dst);
552178481Sjb
553178481Sjb		/*
554178481Sjb		 * If this file has program headers, we need to explicitly lay
555178481Sjb		 * out sections.  If none of the sections prior to this one have
556178481Sjb		 * been removed, then we can just use the existing location.  If
557178481Sjb		 * one or more sections have been changed, then we need to
558178481Sjb		 * adjust this one to avoid holes.
559178481Sjb		 */
560178481Sjb		if (changing && sehdr.e_phnum != 0) {
561178481Sjb			pad = new_offset % shdr.sh_addralign;
562178481Sjb
563178481Sjb			if (pad)
564178481Sjb				new_offset += shdr.sh_addralign - pad;
565178481Sjb			shdr.sh_offset = new_offset;
566178481Sjb		}
567178481Sjb
568178481Sjb		shdr.sh_link = secxlate[shdr.sh_link];
569178481Sjb
570178481Sjb		if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
571178481Sjb			shdr.sh_info = secxlate[shdr.sh_info];
572178481Sjb
573178481Sjb		sname = elf_strptr(src, sehdr.e_shstrndx, shdr.sh_name);
574178481Sjb		if (sname == NULL) {
575178481Sjb			elfterminate(srcname, "Can't find string at %u",
576178481Sjb			    shdr.sh_name);
577178481Sjb		}
578178546Sjb
579178546Sjb#if !defined(sun)
580178546Sjb		if (gelf_update_shdr(dscn, &shdr) == 0)
581178546Sjb			elfterminate(dstname, "Cannot update sect %s", sname);
582178546Sjb#endif
583178546Sjb
584178481Sjb		if ((sdata = elf_getdata(sscn, NULL)) == NULL)
585178481Sjb			elfterminate(srcname, "Cannot get sect %s data", sname);
586178481Sjb		if ((ddata = elf_newdata(dscn)) == NULL)
587178481Sjb			elfterminate(dstname, "Can't make sect %s data", sname);
588178546Sjb#if defined(sun)
589178481Sjb		bcopy(sdata, ddata, sizeof (Elf_Data));
590178546Sjb#else
591178546Sjb		/*
592178546Sjb		 * FreeBSD's Elf_Data has private fields which the
593178546Sjb		 * elf_* routines manage. Simply copying the
594178546Sjb		 * entire structure corrupts the data. So we need
595178546Sjb		 * to copy the public fields explictly.
596178546Sjb		 */
597178546Sjb		ddata->d_align = sdata->d_align;
598178546Sjb		ddata->d_off = sdata->d_off;
599178546Sjb		ddata->d_size = sdata->d_size;
600178546Sjb		ddata->d_type = sdata->d_type;
601178546Sjb		ddata->d_version = sdata->d_version;
602178546Sjb#endif
603178481Sjb
604178481Sjb		if (srcidx == sehdr.e_shstrndx) {
605178481Sjb			char seclen = strlen(CTF_ELF_SCN_NAME);
606178481Sjb
607178481Sjb			ddata->d_buf = xmalloc(ddata->d_size + shdr.sh_size +
608178481Sjb			    seclen + 1);
609178481Sjb			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
610178481Sjb			strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
611178481Sjb			    CTF_ELF_SCN_NAME);
612178481Sjb			ctfnameoff = (off_t)shdr.sh_size;
613178481Sjb			shdr.sh_size += seclen + 1;
614178481Sjb			ddata->d_size += seclen + 1;
615178481Sjb
616178481Sjb			if (sehdr.e_phnum != 0)
617178481Sjb				changing = 1;
618178481Sjb		}
619178481Sjb
620178481Sjb		if (shdr.sh_type == symtab_type && shdr.sh_entsize != 0) {
621178481Sjb			int nsym = shdr.sh_size / shdr.sh_entsize;
622178481Sjb
623178481Sjb			symtab_idx = secxlate[srcidx];
624178481Sjb
625178481Sjb			ddata->d_buf = xmalloc(shdr.sh_size);
626178481Sjb			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
627178481Sjb
628178481Sjb			for (i = 0; i < nsym; i++) {
629178481Sjb				GElf_Sym sym;
630178481Sjb				short newscn;
631178481Sjb
632178546Sjb				if (gelf_getsym(ddata, i, &sym) == NULL)
633178546Sjb					printf("Could not get symbol %d\n",i);
634178481Sjb
635178481Sjb				if (sym.st_shndx >= SHN_LORESERVE)
636178481Sjb					continue;
637178481Sjb
638178481Sjb				if ((newscn = secxlate[sym.st_shndx]) !=
639178481Sjb				    sym.st_shndx) {
640178481Sjb					sym.st_shndx =
641178481Sjb					    (newscn == -1 ? 1 : newscn);
642178481Sjb
643178481Sjb					gelf_update_sym(ddata, i, &sym);
644178481Sjb				}
645178481Sjb			}
646178481Sjb		}
647178481Sjb
648178546Sjb#if !defined(sun)
649210438Snp		if (ddata->d_buf == NULL && sdata->d_buf != NULL) {
650178546Sjb			ddata->d_buf = xmalloc(shdr.sh_size);
651178546Sjb			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
652178546Sjb		}
653178546Sjb#endif
654178546Sjb
655178546Sjb		if (gelf_update_shdr(dscn, &shdr) == 0)
656178481Sjb			elfterminate(dstname, "Cannot update sect %s", sname);
657178481Sjb
658178481Sjb		new_offset = (off_t)shdr.sh_offset;
659178481Sjb		if (shdr.sh_type != SHT_NOBITS)
660178481Sjb			new_offset += shdr.sh_size;
661178481Sjb	}
662178481Sjb
663178481Sjb	if (symtab_idx == -1) {
664178481Sjb		terminate("%s: Cannot find %s section\n", srcname,
665178481Sjb		    dynsym ? "SHT_DYNSYM" : "SHT_SYMTAB");
666178481Sjb	}
667178481Sjb
668178481Sjb	/* Add the ctf section */
669178481Sjb	dscn = elf_newscn(dst);
670178481Sjb	gelf_getshdr(dscn, &shdr);
671178481Sjb	shdr.sh_name = ctfnameoff;
672178481Sjb	shdr.sh_type = SHT_PROGBITS;
673178481Sjb	shdr.sh_size = ctfsize;
674178481Sjb	shdr.sh_link = symtab_idx;
675178481Sjb	shdr.sh_addralign = 4;
676178481Sjb	if (changing && sehdr.e_phnum != 0) {
677178481Sjb		pad = new_offset % shdr.sh_addralign;
678178481Sjb
679178481Sjb		if (pad)
680178481Sjb			new_offset += shdr.sh_addralign - pad;
681178481Sjb
682178481Sjb		shdr.sh_offset = new_offset;
683178481Sjb		new_offset += shdr.sh_size;
684178481Sjb	}
685178481Sjb
686178481Sjb	ddata = elf_newdata(dscn);
687178481Sjb	ddata->d_buf = ctfdata;
688178481Sjb	ddata->d_size = ctfsize;
689178481Sjb	ddata->d_align = shdr.sh_addralign;
690178546Sjb	ddata->d_off = 0;
691178481Sjb
692178481Sjb	gelf_update_shdr(dscn, &shdr);
693178481Sjb
694178481Sjb	/* update the section header location */
695178481Sjb	if (sehdr.e_phnum != 0) {
696178481Sjb		size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
697178481Sjb		size_t r = new_offset % align;
698178481Sjb
699178481Sjb		if (r)
700178481Sjb			new_offset += align - r;
701178481Sjb
702178481Sjb		dehdr.e_shoff = new_offset;
703178481Sjb	}
704178481Sjb
705178481Sjb	/* commit to disk */
706178481Sjb	dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
707178481Sjb	gelf_update_ehdr(dst, &dehdr);
708178481Sjb	if (elf_update(dst, ELF_C_WRITE) < 0)
709178481Sjb		elfterminate(dstname, "Cannot finalize temp file");
710178481Sjb
711178481Sjb	free(secxlate);
712178481Sjb}
713178481Sjb
714178481Sjbstatic caddr_t
715178481Sjbmake_ctf_data(tdata_t *td, Elf *elf, const char *file, size_t *lenp, int flags)
716178481Sjb{
717178481Sjb	iiburst_t *iiburst;
718178481Sjb	caddr_t data;
719178481Sjb
720178481Sjb	iiburst = sort_iidescs(elf, file, td, flags & CTF_FUZZY_MATCH,
721178481Sjb	    flags & CTF_USE_DYNSYM);
722233407Sgonzo	data = ctf_gen(iiburst, lenp, flags & (CTF_COMPRESS |  CTF_SWAP_BYTES));
723178481Sjb
724178481Sjb	iiburst_free(iiburst);
725178481Sjb
726178481Sjb	return (data);
727178481Sjb}
728178481Sjb
729178481Sjbvoid
730178481Sjbwrite_ctf(tdata_t *td, const char *curname, const char *newname, int flags)
731178481Sjb{
732178481Sjb	struct stat st;
733178481Sjb	Elf *elf = NULL;
734178481Sjb	Elf *telf = NULL;
735233407Sgonzo	GElf_Ehdr ehdr;
736178481Sjb	caddr_t data;
737178481Sjb	size_t len;
738178481Sjb	int fd = -1;
739178481Sjb	int tfd = -1;
740233407Sgonzo	int byteorder;
741178481Sjb
742178481Sjb	(void) elf_version(EV_CURRENT);
743178481Sjb	if ((fd = open(curname, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
744178481Sjb		terminate("%s: Cannot open for re-reading", curname);
745178481Sjb	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
746178481Sjb		elfterminate(curname, "Cannot re-read");
747178481Sjb
748178481Sjb	if ((tfd = open(newname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
749178481Sjb		terminate("Cannot open temp file %s for writing", newname);
750178481Sjb	if ((telf = elf_begin(tfd, ELF_C_WRITE, NULL)) == NULL)
751178481Sjb		elfterminate(curname, "Cannot write");
752178481Sjb
753233407Sgonzo	if (gelf_getehdr(elf, &ehdr)) {
754233407Sgonzo#if BYTE_ORDER == _BIG_ENDIAN
755233407Sgonzo		byteorder = ELFDATA2MSB;
756233407Sgonzo#else
757233407Sgonzo		byteorder = ELFDATA2LSB;
758233407Sgonzo#endif
759233407Sgonzo		/*
760233407Sgonzo		 * If target and host has the same byte order
761233407Sgonzo		 * clear byte swapping request
762233407Sgonzo		 */
763233407Sgonzo		if  (ehdr.e_ident[EI_DATA] == byteorder)
764233407Sgonzo			flags &= ~CTF_SWAP_BYTES;
765233407Sgonzo	}
766233407Sgonzo	else
767233407Sgonzo		elfterminate(curname, "Failed to get EHDR");
768233407Sgonzo
769178481Sjb	data = make_ctf_data(td, elf, curname, &len, flags);
770178481Sjb	write_file(elf, curname, telf, newname, data, len, flags);
771178481Sjb	free(data);
772178481Sjb
773178481Sjb	elf_end(telf);
774178481Sjb	elf_end(elf);
775178481Sjb	(void) close(fd);
776178481Sjb	(void) close(tfd);
777178481Sjb}
778