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