xref: /titanic_51/usr/src/lib/libctf/common/ctf_elfwrite.c (revision 7fd791373689a6af05e27efec3b1ab556e02aa23)
1*7fd79137SRobert Mustacchi /*
2*7fd79137SRobert Mustacchi  * CDDL HEADER START
3*7fd79137SRobert Mustacchi  *
4*7fd79137SRobert Mustacchi  * The contents of this file are subject to the terms of the
5*7fd79137SRobert Mustacchi  * Common Development and Distribution License (the "License").
6*7fd79137SRobert Mustacchi  * You may not use this file except in compliance with the License.
7*7fd79137SRobert Mustacchi  *
8*7fd79137SRobert Mustacchi  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7fd79137SRobert Mustacchi  * or http://www.opensolaris.org/os/licensing.
10*7fd79137SRobert Mustacchi  * See the License for the specific language governing permissions
11*7fd79137SRobert Mustacchi  * and limitations under the License.
12*7fd79137SRobert Mustacchi  *
13*7fd79137SRobert Mustacchi  * When distributing Covered Code, include this CDDL HEADER in each
14*7fd79137SRobert Mustacchi  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7fd79137SRobert Mustacchi  * If applicable, add the following below this CDDL HEADER, with the
16*7fd79137SRobert Mustacchi  * fields enclosed by brackets "[]" replaced with your own identifying
17*7fd79137SRobert Mustacchi  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7fd79137SRobert Mustacchi  *
19*7fd79137SRobert Mustacchi  * CDDL HEADER END
20*7fd79137SRobert Mustacchi  */
21*7fd79137SRobert Mustacchi /*
22*7fd79137SRobert Mustacchi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*7fd79137SRobert Mustacchi  * Use is subject to license terms.
24*7fd79137SRobert Mustacchi  */
25*7fd79137SRobert Mustacchi /*
26*7fd79137SRobert Mustacchi  * Copyright (c) 2015, Joyent, Inc.
27*7fd79137SRobert Mustacchi  */
28*7fd79137SRobert Mustacchi 
29*7fd79137SRobert Mustacchi /*
30*7fd79137SRobert Mustacchi  * Routines for writing ctf data to elf files.
31*7fd79137SRobert Mustacchi  */
32*7fd79137SRobert Mustacchi 
33*7fd79137SRobert Mustacchi #include <libctf_impl.h>
34*7fd79137SRobert Mustacchi #include <libctf.h>
35*7fd79137SRobert Mustacchi #include <gelf.h>
36*7fd79137SRobert Mustacchi #include <sys/stat.h>
37*7fd79137SRobert Mustacchi #include <sys/types.h>
38*7fd79137SRobert Mustacchi #include <fcntl.h>
39*7fd79137SRobert Mustacchi #include <errno.h>
40*7fd79137SRobert Mustacchi #include <unistd.h>
41*7fd79137SRobert Mustacchi #include <libelf.h>
42*7fd79137SRobert Mustacchi 
43*7fd79137SRobert Mustacchi static int
44*7fd79137SRobert Mustacchi ctf_write_elf(ctf_file_t *fp, Elf *src, Elf *dst, int flags)
45*7fd79137SRobert Mustacchi {
46*7fd79137SRobert Mustacchi 	GElf_Ehdr sehdr, dehdr;
47*7fd79137SRobert Mustacchi 	Elf_Scn *sscn, *dscn;
48*7fd79137SRobert Mustacchi 	Elf_Data *sdata, *ddata;
49*7fd79137SRobert Mustacchi 	GElf_Shdr shdr;
50*7fd79137SRobert Mustacchi 	int symtab_idx = -1;
51*7fd79137SRobert Mustacchi 	off_t new_offset = 0;
52*7fd79137SRobert Mustacchi 	off_t ctfnameoff = 0;
53*7fd79137SRobert Mustacchi 	int compress = (flags & CTF_ELFWRITE_F_COMPRESS);
54*7fd79137SRobert Mustacchi 	int *secxlate = NULL;
55*7fd79137SRobert Mustacchi 	int srcidx, dstidx, pad, i;
56*7fd79137SRobert Mustacchi 	int curnmoff = 0;
57*7fd79137SRobert Mustacchi 	int changing = 0;
58*7fd79137SRobert Mustacchi 	int ret;
59*7fd79137SRobert Mustacchi 	size_t nshdr, nphdr, strndx;
60*7fd79137SRobert Mustacchi 	void *strdatabuf = NULL, *symdatabuf = NULL;
61*7fd79137SRobert Mustacchi 	size_t strdatasz = 0, symdatasz = 0;
62*7fd79137SRobert Mustacchi 
63*7fd79137SRobert Mustacchi 	void *cdata = NULL;
64*7fd79137SRobert Mustacchi 	size_t elfsize, asize;
65*7fd79137SRobert Mustacchi 
66*7fd79137SRobert Mustacchi 	if ((flags & ~(CTF_ELFWRITE_F_COMPRESS)) != 0) {
67*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, EINVAL);
68*7fd79137SRobert Mustacchi 		goto out;
69*7fd79137SRobert Mustacchi 	}
70*7fd79137SRobert Mustacchi 
71*7fd79137SRobert Mustacchi 	if (gelf_newehdr(dst, gelf_getclass(src)) == NULL) {
72*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
73*7fd79137SRobert Mustacchi 		goto out;
74*7fd79137SRobert Mustacchi 	}
75*7fd79137SRobert Mustacchi 	if (gelf_getehdr(src, &sehdr) == NULL) {
76*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
77*7fd79137SRobert Mustacchi 		goto out;
78*7fd79137SRobert Mustacchi 	}
79*7fd79137SRobert Mustacchi 	(void) memcpy(&dehdr, &sehdr, sizeof (GElf_Ehdr));
80*7fd79137SRobert Mustacchi 	if (gelf_update_ehdr(dst, &dehdr) == 0) {
81*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
82*7fd79137SRobert Mustacchi 		goto out;
83*7fd79137SRobert Mustacchi 	}
84*7fd79137SRobert Mustacchi 
85*7fd79137SRobert Mustacchi 	/*
86*7fd79137SRobert Mustacchi 	 * Use libelf to get the number of sections and the string section to
87*7fd79137SRobert Mustacchi 	 * deal with ELF files that may have a large number of sections. We just
88*7fd79137SRobert Mustacchi 	 * always use this to make our live easier.
89*7fd79137SRobert Mustacchi 	 */
90*7fd79137SRobert Mustacchi 	if (elf_getphdrnum(src, &nphdr) != 0) {
91*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
92*7fd79137SRobert Mustacchi 		goto out;
93*7fd79137SRobert Mustacchi 	}
94*7fd79137SRobert Mustacchi 	if (elf_getshdrnum(src, &nshdr) != 0) {
95*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
96*7fd79137SRobert Mustacchi 		goto out;
97*7fd79137SRobert Mustacchi 	}
98*7fd79137SRobert Mustacchi 	if (elf_getshdrstrndx(src, &strndx) != 0) {
99*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
100*7fd79137SRobert Mustacchi 		goto out;
101*7fd79137SRobert Mustacchi 	}
102*7fd79137SRobert Mustacchi 
103*7fd79137SRobert Mustacchi 	/*
104*7fd79137SRobert Mustacchi 	 * Neither the existing debug sections nor the SUNW_ctf sections (new or
105*7fd79137SRobert Mustacchi 	 * existing) are SHF_ALLOC'd, so they won't be in areas referenced by
106*7fd79137SRobert Mustacchi 	 * program headers.  As such, we can just blindly copy the program
107*7fd79137SRobert Mustacchi 	 * headers from the existing file to the new file.
108*7fd79137SRobert Mustacchi 	 */
109*7fd79137SRobert Mustacchi 	if (nphdr != 0) {
110*7fd79137SRobert Mustacchi 		(void) elf_flagelf(dst, ELF_C_SET, ELF_F_LAYOUT);
111*7fd79137SRobert Mustacchi 		if (gelf_newphdr(dst, nphdr) == NULL) {
112*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
113*7fd79137SRobert Mustacchi 			goto out;
114*7fd79137SRobert Mustacchi 		}
115*7fd79137SRobert Mustacchi 
116*7fd79137SRobert Mustacchi 		for (i = 0; i < nphdr; i++) {
117*7fd79137SRobert Mustacchi 			GElf_Phdr phdr;
118*7fd79137SRobert Mustacchi 
119*7fd79137SRobert Mustacchi 			if (gelf_getphdr(src, i, &phdr) == NULL) {
120*7fd79137SRobert Mustacchi 				ret = ctf_set_errno(fp, ECTF_ELF);
121*7fd79137SRobert Mustacchi 				goto out;
122*7fd79137SRobert Mustacchi 			}
123*7fd79137SRobert Mustacchi 			if (gelf_update_phdr(dst, i, &phdr) == 0) {
124*7fd79137SRobert Mustacchi 				ret = ctf_set_errno(fp, ECTF_ELF);
125*7fd79137SRobert Mustacchi 				goto out;
126*7fd79137SRobert Mustacchi 			}
127*7fd79137SRobert Mustacchi 		}
128*7fd79137SRobert Mustacchi 	}
129*7fd79137SRobert Mustacchi 
130*7fd79137SRobert Mustacchi 	secxlate = ctf_alloc(sizeof (int) * nshdr);
131*7fd79137SRobert Mustacchi 	for (srcidx = dstidx = 0; srcidx < nshdr; srcidx++) {
132*7fd79137SRobert Mustacchi 		Elf_Scn *scn = elf_getscn(src, srcidx);
133*7fd79137SRobert Mustacchi 		GElf_Shdr shdr;
134*7fd79137SRobert Mustacchi 		char *sname;
135*7fd79137SRobert Mustacchi 
136*7fd79137SRobert Mustacchi 		if (gelf_getshdr(scn, &shdr) == NULL) {
137*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
138*7fd79137SRobert Mustacchi 			goto out;
139*7fd79137SRobert Mustacchi 		}
140*7fd79137SRobert Mustacchi 		sname = elf_strptr(src, strndx, shdr.sh_name);
141*7fd79137SRobert Mustacchi 		if (sname == NULL) {
142*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
143*7fd79137SRobert Mustacchi 			goto out;
144*7fd79137SRobert Mustacchi 		}
145*7fd79137SRobert Mustacchi 
146*7fd79137SRobert Mustacchi 		if (strcmp(sname, CTF_ELF_SCN_NAME) == 0) {
147*7fd79137SRobert Mustacchi 			secxlate[srcidx] = -1;
148*7fd79137SRobert Mustacchi 		} else {
149*7fd79137SRobert Mustacchi 			secxlate[srcidx] = dstidx++;
150*7fd79137SRobert Mustacchi 			curnmoff += strlen(sname) + 1;
151*7fd79137SRobert Mustacchi 		}
152*7fd79137SRobert Mustacchi 
153*7fd79137SRobert Mustacchi 		new_offset = (off_t)dehdr.e_phoff;
154*7fd79137SRobert Mustacchi 	}
155*7fd79137SRobert Mustacchi 
156*7fd79137SRobert Mustacchi 	for (srcidx = 1; srcidx < nshdr; srcidx++) {
157*7fd79137SRobert Mustacchi 		char *sname;
158*7fd79137SRobert Mustacchi 
159*7fd79137SRobert Mustacchi 		sscn = elf_getscn(src, srcidx);
160*7fd79137SRobert Mustacchi 		if (gelf_getshdr(sscn, &shdr) == NULL) {
161*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
162*7fd79137SRobert Mustacchi 			goto out;
163*7fd79137SRobert Mustacchi 		}
164*7fd79137SRobert Mustacchi 
165*7fd79137SRobert Mustacchi 		if (secxlate[srcidx] == -1) {
166*7fd79137SRobert Mustacchi 			changing = 1;
167*7fd79137SRobert Mustacchi 			continue;
168*7fd79137SRobert Mustacchi 		}
169*7fd79137SRobert Mustacchi 
170*7fd79137SRobert Mustacchi 		dscn = elf_newscn(dst);
171*7fd79137SRobert Mustacchi 		if (dscn == NULL) {
172*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
173*7fd79137SRobert Mustacchi 			goto out;
174*7fd79137SRobert Mustacchi 		}
175*7fd79137SRobert Mustacchi 
176*7fd79137SRobert Mustacchi 		/*
177*7fd79137SRobert Mustacchi 		 * If this file has program headers, we need to explicitly lay
178*7fd79137SRobert Mustacchi 		 * out sections.  If none of the sections prior to this one have
179*7fd79137SRobert Mustacchi 		 * been removed, then we can just use the existing location.  If
180*7fd79137SRobert Mustacchi 		 * one or more sections have been changed, then we need to
181*7fd79137SRobert Mustacchi 		 * adjust this one to avoid holes.
182*7fd79137SRobert Mustacchi 		 */
183*7fd79137SRobert Mustacchi 		if (changing && nphdr != 0) {
184*7fd79137SRobert Mustacchi 			pad = new_offset % shdr.sh_addralign;
185*7fd79137SRobert Mustacchi 
186*7fd79137SRobert Mustacchi 			if (pad != 0)
187*7fd79137SRobert Mustacchi 				new_offset += shdr.sh_addralign - pad;
188*7fd79137SRobert Mustacchi 			shdr.sh_offset = new_offset;
189*7fd79137SRobert Mustacchi 		}
190*7fd79137SRobert Mustacchi 
191*7fd79137SRobert Mustacchi 		shdr.sh_link = secxlate[shdr.sh_link];
192*7fd79137SRobert Mustacchi 
193*7fd79137SRobert Mustacchi 		if (shdr.sh_type == SHT_REL || shdr.sh_type == SHT_RELA)
194*7fd79137SRobert Mustacchi 			shdr.sh_info = secxlate[shdr.sh_info];
195*7fd79137SRobert Mustacchi 
196*7fd79137SRobert Mustacchi 		sname = elf_strptr(src, strndx, shdr.sh_name);
197*7fd79137SRobert Mustacchi 		if (sname == NULL) {
198*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
199*7fd79137SRobert Mustacchi 			goto out;
200*7fd79137SRobert Mustacchi 		}
201*7fd79137SRobert Mustacchi 		if ((sdata = elf_getdata(sscn, NULL)) == NULL) {
202*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
203*7fd79137SRobert Mustacchi 			goto out;
204*7fd79137SRobert Mustacchi 		}
205*7fd79137SRobert Mustacchi 		if ((ddata = elf_newdata(dscn)) == NULL) {
206*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
207*7fd79137SRobert Mustacchi 			goto out;
208*7fd79137SRobert Mustacchi 		}
209*7fd79137SRobert Mustacchi 		bcopy(sdata, ddata, sizeof (Elf_Data));
210*7fd79137SRobert Mustacchi 
211*7fd79137SRobert Mustacchi 		if (srcidx == strndx) {
212*7fd79137SRobert Mustacchi 			char seclen = strlen(CTF_ELF_SCN_NAME);
213*7fd79137SRobert Mustacchi 
214*7fd79137SRobert Mustacchi 			strdatasz = ddata->d_size + shdr.sh_size +
215*7fd79137SRobert Mustacchi 			    seclen + 1;
216*7fd79137SRobert Mustacchi 			ddata->d_buf = strdatabuf = ctf_alloc(strdatasz);
217*7fd79137SRobert Mustacchi 			if (ddata->d_buf == NULL) {
218*7fd79137SRobert Mustacchi 				ret = ctf_set_errno(fp, ECTF_ELF);
219*7fd79137SRobert Mustacchi 				goto out;
220*7fd79137SRobert Mustacchi 			}
221*7fd79137SRobert Mustacchi 			bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
222*7fd79137SRobert Mustacchi 			(void) strcpy((caddr_t)ddata->d_buf + shdr.sh_size,
223*7fd79137SRobert Mustacchi 			    CTF_ELF_SCN_NAME);
224*7fd79137SRobert Mustacchi 			ctfnameoff = (off_t)shdr.sh_size;
225*7fd79137SRobert Mustacchi 			shdr.sh_size += seclen + 1;
226*7fd79137SRobert Mustacchi 			ddata->d_size += seclen + 1;
227*7fd79137SRobert Mustacchi 
228*7fd79137SRobert Mustacchi 			if (nphdr != 0)
229*7fd79137SRobert Mustacchi 				changing = 1;
230*7fd79137SRobert Mustacchi 		}
231*7fd79137SRobert Mustacchi 
232*7fd79137SRobert Mustacchi 		if (shdr.sh_type == SHT_SYMTAB && shdr.sh_entsize != 0) {
233*7fd79137SRobert Mustacchi 			int nsym = shdr.sh_size / shdr.sh_entsize;
234*7fd79137SRobert Mustacchi 
235*7fd79137SRobert Mustacchi 			symtab_idx = secxlate[srcidx];
236*7fd79137SRobert Mustacchi 
237*7fd79137SRobert Mustacchi 			symdatasz = shdr.sh_size;
238*7fd79137SRobert Mustacchi 			ddata->d_buf = symdatabuf = ctf_alloc(symdatasz);
239*7fd79137SRobert Mustacchi 			if (ddata->d_buf == NULL) {
240*7fd79137SRobert Mustacchi 				ret = ctf_set_errno(fp, ECTF_ELF);
241*7fd79137SRobert Mustacchi 				goto out;
242*7fd79137SRobert Mustacchi 			}
243*7fd79137SRobert Mustacchi 			(void) bcopy(sdata->d_buf, ddata->d_buf, shdr.sh_size);
244*7fd79137SRobert Mustacchi 
245*7fd79137SRobert Mustacchi 			for (i = 0; i < nsym; i++) {
246*7fd79137SRobert Mustacchi 				GElf_Sym sym;
247*7fd79137SRobert Mustacchi 				short newscn;
248*7fd79137SRobert Mustacchi 
249*7fd79137SRobert Mustacchi 				(void) gelf_getsym(ddata, i, &sym);
250*7fd79137SRobert Mustacchi 
251*7fd79137SRobert Mustacchi 				if (sym.st_shndx >= SHN_LORESERVE)
252*7fd79137SRobert Mustacchi 					continue;
253*7fd79137SRobert Mustacchi 
254*7fd79137SRobert Mustacchi 				if ((newscn = secxlate[sym.st_shndx]) !=
255*7fd79137SRobert Mustacchi 				    sym.st_shndx) {
256*7fd79137SRobert Mustacchi 					sym.st_shndx =
257*7fd79137SRobert Mustacchi 					    (newscn == -1 ? 1 : newscn);
258*7fd79137SRobert Mustacchi 
259*7fd79137SRobert Mustacchi 					if (gelf_update_sym(ddata, i, &sym) ==
260*7fd79137SRobert Mustacchi 					    0) {
261*7fd79137SRobert Mustacchi 						ret = ctf_set_errno(fp,
262*7fd79137SRobert Mustacchi 						    ECTF_ELF);
263*7fd79137SRobert Mustacchi 						goto out;
264*7fd79137SRobert Mustacchi 					}
265*7fd79137SRobert Mustacchi 				}
266*7fd79137SRobert Mustacchi 			}
267*7fd79137SRobert Mustacchi 		}
268*7fd79137SRobert Mustacchi 
269*7fd79137SRobert Mustacchi 		if (gelf_update_shdr(dscn, &shdr) == NULL) {
270*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, ECTF_ELF);
271*7fd79137SRobert Mustacchi 			goto out;
272*7fd79137SRobert Mustacchi 		}
273*7fd79137SRobert Mustacchi 
274*7fd79137SRobert Mustacchi 		new_offset = (off_t)shdr.sh_offset;
275*7fd79137SRobert Mustacchi 		if (shdr.sh_type != SHT_NOBITS)
276*7fd79137SRobert Mustacchi 			new_offset += shdr.sh_size;
277*7fd79137SRobert Mustacchi 	}
278*7fd79137SRobert Mustacchi 
279*7fd79137SRobert Mustacchi 	if (symtab_idx == -1) {
280*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
281*7fd79137SRobert Mustacchi 		goto out;
282*7fd79137SRobert Mustacchi 	}
283*7fd79137SRobert Mustacchi 
284*7fd79137SRobert Mustacchi 	/* Add the ctf section */
285*7fd79137SRobert Mustacchi 	if ((dscn = elf_newscn(dst)) == NULL) {
286*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
287*7fd79137SRobert Mustacchi 		goto out;
288*7fd79137SRobert Mustacchi 	}
289*7fd79137SRobert Mustacchi 	if (gelf_getshdr(dscn, &shdr) == NULL) {
290*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
291*7fd79137SRobert Mustacchi 		goto out;
292*7fd79137SRobert Mustacchi 	}
293*7fd79137SRobert Mustacchi 	shdr.sh_name = ctfnameoff;
294*7fd79137SRobert Mustacchi 	shdr.sh_type = SHT_PROGBITS;
295*7fd79137SRobert Mustacchi 	shdr.sh_size = fp->ctf_size;
296*7fd79137SRobert Mustacchi 	shdr.sh_link = symtab_idx;
297*7fd79137SRobert Mustacchi 	shdr.sh_addralign = 4;
298*7fd79137SRobert Mustacchi 	if (changing && nphdr != 0) {
299*7fd79137SRobert Mustacchi 		pad = new_offset % shdr.sh_addralign;
300*7fd79137SRobert Mustacchi 
301*7fd79137SRobert Mustacchi 		if (pad)
302*7fd79137SRobert Mustacchi 			new_offset += shdr.sh_addralign - pad;
303*7fd79137SRobert Mustacchi 
304*7fd79137SRobert Mustacchi 		shdr.sh_offset = new_offset;
305*7fd79137SRobert Mustacchi 		new_offset += shdr.sh_size;
306*7fd79137SRobert Mustacchi 	}
307*7fd79137SRobert Mustacchi 
308*7fd79137SRobert Mustacchi 	if ((ddata = elf_newdata(dscn)) == NULL) {
309*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
310*7fd79137SRobert Mustacchi 		goto out;
311*7fd79137SRobert Mustacchi 	}
312*7fd79137SRobert Mustacchi 
313*7fd79137SRobert Mustacchi 	if (compress != 0) {
314*7fd79137SRobert Mustacchi 		int err;
315*7fd79137SRobert Mustacchi 
316*7fd79137SRobert Mustacchi 		if (ctf_zopen(&err) == NULL) {
317*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, err);
318*7fd79137SRobert Mustacchi 			goto out;
319*7fd79137SRobert Mustacchi 		}
320*7fd79137SRobert Mustacchi 
321*7fd79137SRobert Mustacchi 		if ((err = ctf_compress(fp, &cdata, &asize, &elfsize)) != 0) {
322*7fd79137SRobert Mustacchi 			ret = ctf_set_errno(fp, err);
323*7fd79137SRobert Mustacchi 			goto out;
324*7fd79137SRobert Mustacchi 		}
325*7fd79137SRobert Mustacchi 		ddata->d_buf = cdata;
326*7fd79137SRobert Mustacchi 		ddata->d_size = elfsize;
327*7fd79137SRobert Mustacchi 	} else {
328*7fd79137SRobert Mustacchi 		ddata->d_buf = (void *)fp->ctf_base;
329*7fd79137SRobert Mustacchi 		ddata->d_size = fp->ctf_size;
330*7fd79137SRobert Mustacchi 	}
331*7fd79137SRobert Mustacchi 	ddata->d_align = shdr.sh_addralign;
332*7fd79137SRobert Mustacchi 
333*7fd79137SRobert Mustacchi 	if (gelf_update_shdr(dscn, &shdr) == 0) {
334*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
335*7fd79137SRobert Mustacchi 		goto out;
336*7fd79137SRobert Mustacchi 	}
337*7fd79137SRobert Mustacchi 
338*7fd79137SRobert Mustacchi 	/* update the section header location */
339*7fd79137SRobert Mustacchi 	if (nphdr != 0) {
340*7fd79137SRobert Mustacchi 		size_t align = gelf_fsize(dst, ELF_T_ADDR, 1, EV_CURRENT);
341*7fd79137SRobert Mustacchi 		size_t r = new_offset % align;
342*7fd79137SRobert Mustacchi 
343*7fd79137SRobert Mustacchi 		if (r)
344*7fd79137SRobert Mustacchi 			new_offset += align - r;
345*7fd79137SRobert Mustacchi 
346*7fd79137SRobert Mustacchi 		dehdr.e_shoff = new_offset;
347*7fd79137SRobert Mustacchi 	}
348*7fd79137SRobert Mustacchi 
349*7fd79137SRobert Mustacchi 	/* commit to disk */
350*7fd79137SRobert Mustacchi 	if (sehdr.e_shstrndx == SHN_XINDEX)
351*7fd79137SRobert Mustacchi 		dehdr.e_shstrndx = SHN_XINDEX;
352*7fd79137SRobert Mustacchi 	else
353*7fd79137SRobert Mustacchi 		dehdr.e_shstrndx = secxlate[sehdr.e_shstrndx];
354*7fd79137SRobert Mustacchi 	if (gelf_update_ehdr(dst, &dehdr) == NULL) {
355*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
356*7fd79137SRobert Mustacchi 		goto out;
357*7fd79137SRobert Mustacchi 	}
358*7fd79137SRobert Mustacchi 	if (elf_update(dst, ELF_C_WRITE) < 0) {
359*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, ECTF_ELF);
360*7fd79137SRobert Mustacchi 		goto out;
361*7fd79137SRobert Mustacchi 	}
362*7fd79137SRobert Mustacchi 
363*7fd79137SRobert Mustacchi 	ret = 0;
364*7fd79137SRobert Mustacchi 
365*7fd79137SRobert Mustacchi out:
366*7fd79137SRobert Mustacchi 	if (strdatabuf != NULL)
367*7fd79137SRobert Mustacchi 		ctf_free(strdatabuf, strdatasz);
368*7fd79137SRobert Mustacchi 	if (symdatabuf != NULL)
369*7fd79137SRobert Mustacchi 		ctf_free(symdatabuf, symdatasz);
370*7fd79137SRobert Mustacchi 	if (cdata != NULL)
371*7fd79137SRobert Mustacchi 		ctf_data_free(cdata, fp->ctf_size);
372*7fd79137SRobert Mustacchi 	if (secxlate != NULL)
373*7fd79137SRobert Mustacchi 		ctf_free(secxlate, sizeof (int) * nshdr);
374*7fd79137SRobert Mustacchi 
375*7fd79137SRobert Mustacchi 	return (ret);
376*7fd79137SRobert Mustacchi }
377*7fd79137SRobert Mustacchi 
378*7fd79137SRobert Mustacchi int
379*7fd79137SRobert Mustacchi ctf_elffdwrite(ctf_file_t *fp, int ifd, int ofd, int flags)
380*7fd79137SRobert Mustacchi {
381*7fd79137SRobert Mustacchi 	int ret;
382*7fd79137SRobert Mustacchi 	Elf *ielf, *oelf;
383*7fd79137SRobert Mustacchi 
384*7fd79137SRobert Mustacchi 	(void) elf_version(EV_CURRENT);
385*7fd79137SRobert Mustacchi 	if ((ielf = elf_begin(ifd, ELF_C_READ, NULL)) == NULL)
386*7fd79137SRobert Mustacchi 		return (ctf_set_errno(fp, ECTF_ELF));
387*7fd79137SRobert Mustacchi 
388*7fd79137SRobert Mustacchi 	if ((oelf = elf_begin(ofd, ELF_C_WRITE, NULL)) == NULL)
389*7fd79137SRobert Mustacchi 		return (ctf_set_errno(fp, ECTF_ELF));
390*7fd79137SRobert Mustacchi 
391*7fd79137SRobert Mustacchi 	ret = ctf_write_elf(fp, ielf, oelf, flags);
392*7fd79137SRobert Mustacchi 
393*7fd79137SRobert Mustacchi 	(void) elf_end(ielf);
394*7fd79137SRobert Mustacchi 	(void) elf_end(oelf);
395*7fd79137SRobert Mustacchi 
396*7fd79137SRobert Mustacchi 	return (ret);
397*7fd79137SRobert Mustacchi }
398*7fd79137SRobert Mustacchi 
399*7fd79137SRobert Mustacchi int
400*7fd79137SRobert Mustacchi ctf_elfwrite(ctf_file_t *fp, const char *input, const char *output, int flags)
401*7fd79137SRobert Mustacchi {
402*7fd79137SRobert Mustacchi 	struct stat st;
403*7fd79137SRobert Mustacchi 	int ifd, ofd, ret;
404*7fd79137SRobert Mustacchi 
405*7fd79137SRobert Mustacchi 	if ((ifd = open(input, O_RDONLY)) < 0)
406*7fd79137SRobert Mustacchi 		return (ctf_set_errno(fp, errno));
407*7fd79137SRobert Mustacchi 
408*7fd79137SRobert Mustacchi 	if (fstat(ifd, &st) < 0)
409*7fd79137SRobert Mustacchi 		return (ctf_set_errno(fp, errno));
410*7fd79137SRobert Mustacchi 
411*7fd79137SRobert Mustacchi 	if ((ofd = open(output, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0)
412*7fd79137SRobert Mustacchi 		return (ctf_set_errno(fp, errno));
413*7fd79137SRobert Mustacchi 
414*7fd79137SRobert Mustacchi 	ret = ctf_elffdwrite(fp, ifd, ofd, flags);
415*7fd79137SRobert Mustacchi 
416*7fd79137SRobert Mustacchi 	if (close(ifd) != 0 && ret == 0)
417*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, errno);
418*7fd79137SRobert Mustacchi 	if (close(ofd) != 0 && ret == 0)
419*7fd79137SRobert Mustacchi 		ret = ctf_set_errno(fp, errno);
420*7fd79137SRobert Mustacchi 
421*7fd79137SRobert Mustacchi 	return (ret);
422*7fd79137SRobert Mustacchi }
423