xref: /freebsd/contrib/elftoolchain/elfcopy/sections.c (revision 95fd7f26154281528fc8fc01fd29e961a054555f)
1a85fe12eSEd Maste /*-
24a85c691SEd Maste  * Copyright (c) 2007-2011,2014 Kai Wang
3a85fe12eSEd Maste  * All rights reserved.
4a85fe12eSEd Maste  *
5a85fe12eSEd Maste  * Redistribution and use in source and binary forms, with or without
6a85fe12eSEd Maste  * modification, are permitted provided that the following conditions
7a85fe12eSEd Maste  * are met:
8a85fe12eSEd Maste  * 1. Redistributions of source code must retain the above copyright
9a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer.
10a85fe12eSEd Maste  * 2. Redistributions in binary form must reproduce the above copyright
11a85fe12eSEd Maste  *    notice, this list of conditions and the following disclaimer in the
12a85fe12eSEd Maste  *    documentation and/or other materials provided with the distribution.
13a85fe12eSEd Maste  *
14a85fe12eSEd Maste  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15a85fe12eSEd Maste  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16a85fe12eSEd Maste  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17a85fe12eSEd Maste  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18a85fe12eSEd Maste  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19a85fe12eSEd Maste  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20a85fe12eSEd Maste  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21a85fe12eSEd Maste  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22a85fe12eSEd Maste  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23a85fe12eSEd Maste  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24a85fe12eSEd Maste  * SUCH DAMAGE.
25a85fe12eSEd Maste  */
26a85fe12eSEd Maste 
27a85fe12eSEd Maste #include <sys/param.h>
28a85fe12eSEd Maste #include <sys/stat.h>
29a85fe12eSEd Maste #include <err.h>
30a85fe12eSEd Maste #include <libgen.h>
31a85fe12eSEd Maste #include <stdio.h>
32a85fe12eSEd Maste #include <stdlib.h>
33a85fe12eSEd Maste #include <string.h>
34a85fe12eSEd Maste 
35a85fe12eSEd Maste #include "elfcopy.h"
36a85fe12eSEd Maste 
37*95fd7f26SEd Maste ELFTC_VCSID("$Id: sections.c 3272 2015-12-11 20:00:54Z kaiwang27 $");
38a85fe12eSEd Maste 
39a85fe12eSEd Maste static void	add_gnu_debuglink(struct elfcopy *ecp);
40a85fe12eSEd Maste static uint32_t calc_crc32(const char *p, size_t len, uint32_t crc);
41a85fe12eSEd Maste static void	check_section_rename(struct elfcopy *ecp, struct section *s);
42a85fe12eSEd Maste static void	filter_reloc(struct elfcopy *ecp, struct section *s);
43a85fe12eSEd Maste static int	get_section_flags(struct elfcopy *ecp, const char *name);
44a85fe12eSEd Maste static void	insert_sections(struct elfcopy *ecp);
45a85fe12eSEd Maste static void	insert_to_strtab(struct section *t, const char *s);
46a85fe12eSEd Maste static int	is_append_section(struct elfcopy *ecp, const char *name);
47a85fe12eSEd Maste static int	is_compress_section(struct elfcopy *ecp, const char *name);
48a85fe12eSEd Maste static int	is_debug_section(const char *name);
4967d97fe7SEd Maste static int	is_dwo_section(const char *name);
50a85fe12eSEd Maste static int	is_modify_section(struct elfcopy *ecp, const char *name);
51a85fe12eSEd Maste static int	is_print_section(struct elfcopy *ecp, const char *name);
52a85fe12eSEd Maste static int	lookup_string(struct section *t, const char *s);
53a85fe12eSEd Maste static void	modify_section(struct elfcopy *ecp, struct section *s);
54a85fe12eSEd Maste static void	pad_section(struct elfcopy *ecp, struct section *s);
55a85fe12eSEd Maste static void	print_data(const char *d, size_t sz);
56a85fe12eSEd Maste static void	print_section(struct section *s);
57a85fe12eSEd Maste static void	*read_section(struct section *s, size_t *size);
58a85fe12eSEd Maste static void	update_reloc(struct elfcopy *ecp, struct section *s);
593ef90571SEd Maste static void	update_section_group(struct elfcopy *ecp, struct section *s);
60a85fe12eSEd Maste 
61a85fe12eSEd Maste int
62a85fe12eSEd Maste is_remove_section(struct elfcopy *ecp, const char *name)
63a85fe12eSEd Maste {
64a85fe12eSEd Maste 
65a85fe12eSEd Maste 	/* Always keep section name table */
66a85fe12eSEd Maste 	if (strcmp(name, ".shstrtab") == 0)
67a85fe12eSEd Maste 		return 0;
68a85fe12eSEd Maste 	if (strcmp(name, ".symtab") == 0 ||
69a85fe12eSEd Maste 	    strcmp(name, ".strtab") == 0) {
70a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL && lookup_symop_list(
71a85fe12eSEd Maste 		    ecp, NULL, SYMOP_KEEP) == NULL)
72a85fe12eSEd Maste 			return (1);
73a85fe12eSEd Maste 		else
74a85fe12eSEd Maste 			return (0);
75a85fe12eSEd Maste 	}
76a85fe12eSEd Maste 
7767d97fe7SEd Maste 	if (ecp->strip == STRIP_DWO && is_dwo_section(name))
7867d97fe7SEd Maste 		return (1);
7967d97fe7SEd Maste 	if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name))
8067d97fe7SEd Maste 		return (1);
8167d97fe7SEd Maste 
82a85fe12eSEd Maste 	if (is_debug_section(name)) {
83a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL ||
84a85fe12eSEd Maste 		    ecp->strip == STRIP_DEBUG ||
85a85fe12eSEd Maste 		    ecp->strip == STRIP_UNNEEDED ||
86a85fe12eSEd Maste 		    (ecp->flags & DISCARD_LOCAL))
87a85fe12eSEd Maste 			return (1);
88a85fe12eSEd Maste 		if (ecp->strip == STRIP_NONDEBUG)
89a85fe12eSEd Maste 			return (0);
90a85fe12eSEd Maste 	}
91a85fe12eSEd Maste 
92a85fe12eSEd Maste 	if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) {
93a85fe12eSEd Maste 		struct sec_action *sac;
94a85fe12eSEd Maste 
95a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, name, 0);
96a85fe12eSEd Maste 		if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove)
97a85fe12eSEd Maste 			return (1);
98a85fe12eSEd Maste 		if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy))
99a85fe12eSEd Maste 			return (1);
100a85fe12eSEd Maste 	}
101a85fe12eSEd Maste 
102a85fe12eSEd Maste 	return (0);
103a85fe12eSEd Maste }
104a85fe12eSEd Maste 
105a85fe12eSEd Maste /*
106a85fe12eSEd Maste  * Relocation section needs to be removed if the section it applies to
107a85fe12eSEd Maste  * will be removed.
108a85fe12eSEd Maste  */
109a85fe12eSEd Maste int
110a85fe12eSEd Maste is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)
111a85fe12eSEd Maste {
112a85fe12eSEd Maste 	const char	*name;
113a85fe12eSEd Maste 	GElf_Shdr	 ish;
114a85fe12eSEd Maste 	Elf_Scn		*is;
115a85fe12eSEd Maste 	size_t		 indx;
116a85fe12eSEd Maste 	int		 elferr;
117a85fe12eSEd Maste 
118a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
119a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
120a85fe12eSEd Maste 		    elf_errmsg(-1));
121a85fe12eSEd Maste 
122a85fe12eSEd Maste 	is = NULL;
123a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
124a85fe12eSEd Maste 		if (sh_info == elf_ndxscn(is)) {
125a85fe12eSEd Maste 			if (gelf_getshdr(is, &ish) == NULL)
126a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
127a85fe12eSEd Maste 				    elf_errmsg(-1));
128a85fe12eSEd Maste 			if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
129a85fe12eSEd Maste 			    NULL)
130a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_strptr failed: %s",
131a85fe12eSEd Maste 				    elf_errmsg(-1));
132a85fe12eSEd Maste 			if (is_remove_section(ecp, name))
133a85fe12eSEd Maste 				return (1);
134a85fe12eSEd Maste 			else
135a85fe12eSEd Maste 				return (0);
136a85fe12eSEd Maste 		}
137a85fe12eSEd Maste 	}
138a85fe12eSEd Maste 	elferr = elf_errno();
139a85fe12eSEd Maste 	if (elferr != 0)
140a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
141a85fe12eSEd Maste 		    elf_errmsg(elferr));
142a85fe12eSEd Maste 
143a85fe12eSEd Maste 	/* Remove reloc section if we can't find the target section. */
144a85fe12eSEd Maste 	return (1);
145a85fe12eSEd Maste }
146a85fe12eSEd Maste 
147a85fe12eSEd Maste static int
148a85fe12eSEd Maste is_append_section(struct elfcopy *ecp, const char *name)
149a85fe12eSEd Maste {
150a85fe12eSEd Maste 	struct sec_action *sac;
151a85fe12eSEd Maste 
152a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
153a85fe12eSEd Maste 	if (sac != NULL && sac->append != 0 && sac->string != NULL)
154a85fe12eSEd Maste 		return (1);
155a85fe12eSEd Maste 
156a85fe12eSEd Maste 	return (0);
157a85fe12eSEd Maste }
158a85fe12eSEd Maste 
159a85fe12eSEd Maste static int
160a85fe12eSEd Maste is_compress_section(struct elfcopy *ecp, const char *name)
161a85fe12eSEd Maste {
162a85fe12eSEd Maste 	struct sec_action *sac;
163a85fe12eSEd Maste 
164a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
165a85fe12eSEd Maste 	if (sac != NULL && sac->compress != 0)
166a85fe12eSEd Maste 		return (1);
167a85fe12eSEd Maste 
168a85fe12eSEd Maste 	return (0);
169a85fe12eSEd Maste }
170a85fe12eSEd Maste 
171a85fe12eSEd Maste static void
172a85fe12eSEd Maste check_section_rename(struct elfcopy *ecp, struct section *s)
173a85fe12eSEd Maste {
174a85fe12eSEd Maste 	struct sec_action *sac;
175a85fe12eSEd Maste 	char *prefix;
176a85fe12eSEd Maste 	size_t namelen;
177a85fe12eSEd Maste 
178a85fe12eSEd Maste 	if (s->pseudo)
179a85fe12eSEd Maste 		return;
180a85fe12eSEd Maste 
181a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, s->name, 0);
182a85fe12eSEd Maste 	if (sac != NULL && sac->rename)
183a85fe12eSEd Maste 		s->name = sac->newname;
184a85fe12eSEd Maste 
185a85fe12eSEd Maste 	if (!strcmp(s->name, ".symtab") ||
186a85fe12eSEd Maste 	    !strcmp(s->name, ".strtab") ||
187a85fe12eSEd Maste 	    !strcmp(s->name, ".shstrtab"))
188a85fe12eSEd Maste 		return;
189a85fe12eSEd Maste 
190a85fe12eSEd Maste 	prefix = NULL;
191a85fe12eSEd Maste 	if (s->loadable && ecp->prefix_alloc != NULL)
192a85fe12eSEd Maste 		prefix = ecp->prefix_alloc;
193a85fe12eSEd Maste 	else if (ecp->prefix_sec != NULL)
194a85fe12eSEd Maste 		prefix = ecp->prefix_sec;
195a85fe12eSEd Maste 
196a85fe12eSEd Maste 	if (prefix != NULL) {
197a85fe12eSEd Maste 		namelen = strlen(s->name) + strlen(prefix) + 1;
198a85fe12eSEd Maste 		if ((s->newname = malloc(namelen)) == NULL)
199a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
200a85fe12eSEd Maste 		snprintf(s->newname, namelen, "%s%s", prefix, s->name);
201a85fe12eSEd Maste 		s->name = s->newname;
202a85fe12eSEd Maste 	}
203a85fe12eSEd Maste }
204a85fe12eSEd Maste 
205a85fe12eSEd Maste static int
206a85fe12eSEd Maste get_section_flags(struct elfcopy *ecp, const char *name)
207a85fe12eSEd Maste {
208a85fe12eSEd Maste 	struct sec_action *sac;
209a85fe12eSEd Maste 
210a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
211a85fe12eSEd Maste 	if (sac != NULL && sac->flags)
212a85fe12eSEd Maste 		return sac->flags;
213a85fe12eSEd Maste 
214a85fe12eSEd Maste 	return (0);
215a85fe12eSEd Maste }
216a85fe12eSEd Maste 
217a85fe12eSEd Maste /*
218a85fe12eSEd Maste  * Determine whether the section are debugging section.
219a85fe12eSEd Maste  * According to libbfd, debugging sections are recognized
220a85fe12eSEd Maste  * only by name.
221a85fe12eSEd Maste  */
222a85fe12eSEd Maste static int
223a85fe12eSEd Maste is_debug_section(const char *name)
224a85fe12eSEd Maste {
225a85fe12eSEd Maste 	const char *dbg_sec[] = {
226a85fe12eSEd Maste 		".debug",
227a85fe12eSEd Maste 		".gnu.linkonce.wi.",
228a85fe12eSEd Maste 		".line",
229a85fe12eSEd Maste 		".stab",
230a85fe12eSEd Maste 		NULL
231a85fe12eSEd Maste 	};
232a85fe12eSEd Maste 	const char **p;
233a85fe12eSEd Maste 
234a85fe12eSEd Maste 	for(p = dbg_sec; *p; p++) {
235a85fe12eSEd Maste 		if (strncmp(name, *p, strlen(*p)) == 0)
236a85fe12eSEd Maste 			return (1);
237a85fe12eSEd Maste 	}
238a85fe12eSEd Maste 
239a85fe12eSEd Maste 	return (0);
240a85fe12eSEd Maste }
241a85fe12eSEd Maste 
242a85fe12eSEd Maste static int
24367d97fe7SEd Maste is_dwo_section(const char *name)
24467d97fe7SEd Maste {
24567d97fe7SEd Maste 	size_t len;
24667d97fe7SEd Maste 
24767d97fe7SEd Maste 	if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)
24867d97fe7SEd Maste 		return (1);
24967d97fe7SEd Maste 	return (0);
25067d97fe7SEd Maste }
25167d97fe7SEd Maste 
25267d97fe7SEd Maste static int
253a85fe12eSEd Maste is_print_section(struct elfcopy *ecp, const char *name)
254a85fe12eSEd Maste {
255a85fe12eSEd Maste 	struct sec_action *sac;
256a85fe12eSEd Maste 
257a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
258a85fe12eSEd Maste 	if (sac != NULL && sac->print != 0)
259a85fe12eSEd Maste 		return (1);
260a85fe12eSEd Maste 
261a85fe12eSEd Maste 	return (0);
262a85fe12eSEd Maste }
263a85fe12eSEd Maste 
264a85fe12eSEd Maste static int
265a85fe12eSEd Maste is_modify_section(struct elfcopy *ecp, const char *name)
266a85fe12eSEd Maste {
267a85fe12eSEd Maste 
268a85fe12eSEd Maste 	if (is_append_section(ecp, name) ||
269a85fe12eSEd Maste 	    is_compress_section(ecp, name))
270a85fe12eSEd Maste 		return (1);
271a85fe12eSEd Maste 
272a85fe12eSEd Maste 	return (0);
273a85fe12eSEd Maste }
274a85fe12eSEd Maste 
275a85fe12eSEd Maste struct sec_action*
276a85fe12eSEd Maste lookup_sec_act(struct elfcopy *ecp, const char *name, int add)
277a85fe12eSEd Maste {
278a85fe12eSEd Maste 	struct sec_action *sac;
279a85fe12eSEd Maste 
280a85fe12eSEd Maste 	if (name == NULL)
281a85fe12eSEd Maste 		return NULL;
282a85fe12eSEd Maste 
283a85fe12eSEd Maste 	STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
284a85fe12eSEd Maste 		if (strcmp(name, sac->name) == 0)
285a85fe12eSEd Maste 			return sac;
286a85fe12eSEd Maste 	}
287a85fe12eSEd Maste 
288a85fe12eSEd Maste 	if (add == 0)
289a85fe12eSEd Maste 		return NULL;
290a85fe12eSEd Maste 
291a85fe12eSEd Maste 	if ((sac = malloc(sizeof(*sac))) == NULL)
292a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
293a85fe12eSEd Maste 	memset(sac, 0, sizeof(*sac));
294a85fe12eSEd Maste 	sac->name = name;
295a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);
296a85fe12eSEd Maste 
297a85fe12eSEd Maste 	return (sac);
298a85fe12eSEd Maste }
299a85fe12eSEd Maste 
300a85fe12eSEd Maste void
301a85fe12eSEd Maste free_sec_act(struct elfcopy *ecp)
302a85fe12eSEd Maste {
303a85fe12eSEd Maste 	struct sec_action *sac, *sac_temp;
304a85fe12eSEd Maste 
305a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {
306a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);
307a85fe12eSEd Maste 		free(sac);
308a85fe12eSEd Maste 	}
309a85fe12eSEd Maste }
310a85fe12eSEd Maste 
311a85fe12eSEd Maste void
312a85fe12eSEd Maste insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
313a85fe12eSEd Maste {
314a85fe12eSEd Maste 	struct section *s;
315a85fe12eSEd Maste 
316a85fe12eSEd Maste 	if (!tail) {
317a85fe12eSEd Maste 		TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
318a85fe12eSEd Maste 			if (sec->off < s->off) {
319a85fe12eSEd Maste 				TAILQ_INSERT_BEFORE(s, sec, sec_list);
320a85fe12eSEd Maste 				goto inc_nos;
321a85fe12eSEd Maste 			}
322a85fe12eSEd Maste 		}
323a85fe12eSEd Maste 	}
324a85fe12eSEd Maste 
325a85fe12eSEd Maste 	TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
326a85fe12eSEd Maste 
327a85fe12eSEd Maste inc_nos:
328a85fe12eSEd Maste 	if (sec->pseudo == 0)
329a85fe12eSEd Maste 		ecp->nos++;
330a85fe12eSEd Maste }
331a85fe12eSEd Maste 
332a85fe12eSEd Maste /*
333a85fe12eSEd Maste  * First step of section creation: create scn and internal section
334a85fe12eSEd Maste  * structure, discard sections to be removed.
335a85fe12eSEd Maste  */
336a85fe12eSEd Maste void
337a85fe12eSEd Maste create_scn(struct elfcopy *ecp)
338a85fe12eSEd Maste {
339a85fe12eSEd Maste 	struct section	*s;
340a85fe12eSEd Maste 	const char	*name;
341a85fe12eSEd Maste 	Elf_Scn		*is;
342a85fe12eSEd Maste 	GElf_Shdr	 ish;
343a85fe12eSEd Maste 	size_t		 indx;
344a85fe12eSEd Maste 	uint64_t	 oldndx, newndx;
345a85fe12eSEd Maste 	int		 elferr, sec_flags;
346a85fe12eSEd Maste 
347a85fe12eSEd Maste 	/*
348a85fe12eSEd Maste 	 * Insert a pseudo section that contains the ELF header
349a85fe12eSEd Maste 	 * and program header. Used as reference for section offset
350a85fe12eSEd Maste 	 * or load address adjustment.
351a85fe12eSEd Maste 	 */
352a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
353a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
354a85fe12eSEd Maste 	s->off = 0;
355a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +
356a85fe12eSEd Maste 	    gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);
357a85fe12eSEd Maste 	s->align = 1;
358a85fe12eSEd Maste 	s->pseudo = 1;
359a85fe12eSEd Maste 	s->loadable = add_to_inseg_list(ecp, s);
360a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 0);
361a85fe12eSEd Maste 
362a85fe12eSEd Maste 	/* Create internal .shstrtab section. */
363a85fe12eSEd Maste 	init_shstrtab(ecp);
364a85fe12eSEd Maste 
365a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
366a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
367a85fe12eSEd Maste 		    elf_errmsg(-1));
368a85fe12eSEd Maste 
369a85fe12eSEd Maste 	is = NULL;
370a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
371a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) == NULL)
372a85fe12eSEd Maste 			errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s",
373a85fe12eSEd Maste 			    elf_errmsg(-1));
374a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL)
375a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
376a85fe12eSEd Maste 			    elf_errmsg(-1));
377a85fe12eSEd Maste 
378a85fe12eSEd Maste 		/* Skip sections to be removed. */
379a85fe12eSEd Maste 		if (is_remove_section(ecp, name))
380a85fe12eSEd Maste 			continue;
381a85fe12eSEd Maste 
382a85fe12eSEd Maste 		/*
383a85fe12eSEd Maste 		 * Relocation section need to be remove if the section
384a85fe12eSEd Maste 		 * it applies will be removed.
385a85fe12eSEd Maste 		 */
386a85fe12eSEd Maste 		if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
387a85fe12eSEd Maste 			if (ish.sh_info != 0 &&
388a85fe12eSEd Maste 			    is_remove_reloc_sec(ecp, ish.sh_info))
389a85fe12eSEd Maste 				continue;
390a85fe12eSEd Maste 
391cf781b2eSEd Maste 		/*
392cf781b2eSEd Maste 		 * Section groups should be removed if symbol table will
393cf781b2eSEd Maste 		 * be removed. (section group's signature stored in symbol
394cf781b2eSEd Maste 		 * table)
395cf781b2eSEd Maste 		 */
396cf781b2eSEd Maste 		if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL)
397cf781b2eSEd Maste 			continue;
398cf781b2eSEd Maste 
399a85fe12eSEd Maste 		/* Get section flags set by user. */
400a85fe12eSEd Maste 		sec_flags = get_section_flags(ecp, name);
401a85fe12eSEd Maste 
402a85fe12eSEd Maste 		/* Create internal section object. */
403a85fe12eSEd Maste 		if (strcmp(name, ".shstrtab") != 0) {
404a85fe12eSEd Maste 			if ((s = calloc(1, sizeof(*s))) == NULL)
405a85fe12eSEd Maste 				err(EXIT_FAILURE, "calloc failed");
406a85fe12eSEd Maste 			s->name		= name;
407a85fe12eSEd Maste 			s->is		= is;
408a85fe12eSEd Maste 			s->off		= ish.sh_offset;
409a85fe12eSEd Maste 			s->sz		= ish.sh_size;
410a85fe12eSEd Maste 			s->align	= ish.sh_addralign;
411a85fe12eSEd Maste 			s->type		= ish.sh_type;
412a85fe12eSEd Maste 			s->vma		= ish.sh_addr;
413a85fe12eSEd Maste 
414a85fe12eSEd Maste 			/*
415a85fe12eSEd Maste 			 * Search program headers to determine whether section
416a85fe12eSEd Maste 			 * is loadable, but if user explicitly set section flags
417a85fe12eSEd Maste 			 * while neither "load" nor "alloc" is set, we make the
418a85fe12eSEd Maste 			 * section unloadable.
419a85fe12eSEd Maste 			 */
420a85fe12eSEd Maste 			if (sec_flags &&
421a85fe12eSEd Maste 			    (sec_flags & (SF_LOAD | SF_ALLOC)) == 0)
422a85fe12eSEd Maste 				s->loadable = 0;
423a85fe12eSEd Maste 			else
424a85fe12eSEd Maste 				s->loadable = add_to_inseg_list(ecp, s);
425a85fe12eSEd Maste 		} else {
426a85fe12eSEd Maste 			/* Assuming .shstrtab is "unloadable". */
427a85fe12eSEd Maste 			s		= ecp->shstrtab;
428a85fe12eSEd Maste 			s->off		= ish.sh_offset;
429a85fe12eSEd Maste 		}
430a85fe12eSEd Maste 
431a85fe12eSEd Maste 		oldndx = newndx = SHN_UNDEF;
432a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
433a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0) {
434a85fe12eSEd Maste 			if (!strcmp(name, ".shstrtab")) {
435a85fe12eSEd Maste 				/*
436a85fe12eSEd Maste 				 * Add sections specified by --add-section and
437a85fe12eSEd Maste 				 * gnu debuglink. we want these sections have
438a85fe12eSEd Maste 				 * smaller index than .shstrtab section.
439a85fe12eSEd Maste 				 */
440a85fe12eSEd Maste 				if (ecp->debuglink != NULL)
441a85fe12eSEd Maste 					add_gnu_debuglink(ecp);
442a85fe12eSEd Maste 				if (ecp->flags & SEC_ADD)
443a85fe12eSEd Maste 					insert_sections(ecp);
444a85fe12eSEd Maste 			}
445a85fe12eSEd Maste  			if ((s->os = elf_newscn(ecp->eout)) == NULL)
446a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_newscn failed: %s",
447a85fe12eSEd Maste 				    elf_errmsg(-1));
448a85fe12eSEd Maste 			if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)
449a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
450a85fe12eSEd Maste 				    elf_errmsg(-1));
451a85fe12eSEd Maste 		}
452a85fe12eSEd Maste 		if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)
453a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
454a85fe12eSEd Maste 			    elf_errmsg(-1));
455a85fe12eSEd Maste 		if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)
456a85fe12eSEd Maste 			ecp->secndx[oldndx] = newndx;
457a85fe12eSEd Maste 
458a85fe12eSEd Maste 		/*
459a85fe12eSEd Maste 		 * If strip action is STRIP_NONDEBUG(only keep debug),
460*95fd7f26SEd Maste 		 * change sections type of loadable sections and section
461*95fd7f26SEd Maste 		 * groups to SHT_NOBITS, and the content of those sections
462*95fd7f26SEd Maste 		 * will be discarded. However, SHT_NOTE sections should
463*95fd7f26SEd Maste 		 * be kept.
464a85fe12eSEd Maste 		 */
465*95fd7f26SEd Maste 		if (ecp->strip == STRIP_NONDEBUG) {
466*95fd7f26SEd Maste 			if (((ish.sh_flags & SHF_ALLOC) ||
467*95fd7f26SEd Maste 			    (ish.sh_flags & SHF_GROUP)) &&
468*95fd7f26SEd Maste 			    ish.sh_type != SHT_NOTE)
469a85fe12eSEd Maste 				s->type = SHT_NOBITS;
470*95fd7f26SEd Maste 		}
471a85fe12eSEd Maste 
472a85fe12eSEd Maste 		check_section_rename(ecp, s);
473a85fe12eSEd Maste 
474a85fe12eSEd Maste 		/* create section header based on input object. */
475a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
476a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0 &&
477a85fe12eSEd Maste 		    strcmp(name, ".shstrtab") != 0)
478a85fe12eSEd Maste 			copy_shdr(ecp, s, NULL, 0, sec_flags);
479a85fe12eSEd Maste 
480a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0) {
481a85fe12eSEd Maste 			ecp->flags |= SYMTAB_EXIST;
482a85fe12eSEd Maste 			ecp->symtab = s;
483a85fe12eSEd Maste 		}
484a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0)
485a85fe12eSEd Maste 			ecp->strtab = s;
486a85fe12eSEd Maste 
487a85fe12eSEd Maste 		insert_to_sec_list(ecp, s, 0);
488a85fe12eSEd Maste 	}
489a85fe12eSEd Maste 	elferr = elf_errno();
490a85fe12eSEd Maste 	if (elferr != 0)
491a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
492a85fe12eSEd Maste 		    elf_errmsg(elferr));
493a85fe12eSEd Maste }
494a85fe12eSEd Maste 
495a85fe12eSEd Maste struct section *
496a85fe12eSEd Maste insert_shtab(struct elfcopy *ecp, int tail)
497a85fe12eSEd Maste {
498a85fe12eSEd Maste 	struct section	*s, *shtab;
499a85fe12eSEd Maste 	GElf_Ehdr	 ieh;
500a85fe12eSEd Maste 	int		 nsecs;
501a85fe12eSEd Maste 
502a85fe12eSEd Maste 	/*
503a85fe12eSEd Maste 	 * Treat section header table as a "pseudo" section, insert it
504a85fe12eSEd Maste 	 * into section list, so later it will get sorted and resynced
505a85fe12eSEd Maste 	 * just as normal sections.
506a85fe12eSEd Maste 	 */
507a85fe12eSEd Maste 	if ((shtab = calloc(1, sizeof(*shtab))) == NULL)
508a85fe12eSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
509a85fe12eSEd Maste 	if (!tail) {
5104a85c691SEd Maste 		/*
5114a85c691SEd Maste 		 * "shoff" of input object is used as a hint for section
5124a85c691SEd Maste 		 * resync later.
5134a85c691SEd Maste 		 */
514a85fe12eSEd Maste 		if (gelf_getehdr(ecp->ein, &ieh) == NULL)
515a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
516a85fe12eSEd Maste 			    elf_errmsg(-1));
517a85fe12eSEd Maste 		shtab->off = ieh.e_shoff;
518a85fe12eSEd Maste 	} else
519a85fe12eSEd Maste 		shtab->off = 0;
520a85fe12eSEd Maste 	/* Calculate number of sections in the output object. */
521a85fe12eSEd Maste 	nsecs = 0;
522a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
523a85fe12eSEd Maste 		if (!s->pseudo)
524a85fe12eSEd Maste 			nsecs++;
525a85fe12eSEd Maste 	}
526a85fe12eSEd Maste 	/* Remember there is always a null section, so we +1 here. */
527a85fe12eSEd Maste 	shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);
528a85fe12eSEd Maste 	if (shtab->sz == 0)
529a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
530a85fe12eSEd Maste 	shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);
531a85fe12eSEd Maste 	shtab->loadable = 0;
532a85fe12eSEd Maste 	shtab->pseudo = 1;
533a85fe12eSEd Maste 	insert_to_sec_list(ecp, shtab, tail);
534a85fe12eSEd Maste 
535a85fe12eSEd Maste 	return (shtab);
536a85fe12eSEd Maste }
537a85fe12eSEd Maste 
538a85fe12eSEd Maste void
539a85fe12eSEd Maste copy_content(struct elfcopy *ecp)
540a85fe12eSEd Maste {
541a85fe12eSEd Maste 	struct section *s;
542a85fe12eSEd Maste 
543a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
544a85fe12eSEd Maste 		/* Skip pseudo section. */
545a85fe12eSEd Maste 		if (s->pseudo)
546a85fe12eSEd Maste 			continue;
547a85fe12eSEd Maste 
548a85fe12eSEd Maste 		/* Skip special sections. */
549a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
550a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
551a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
552a85fe12eSEd Maste 			continue;
553a85fe12eSEd Maste 
554a85fe12eSEd Maste 		/*
555a85fe12eSEd Maste 		 * If strip action is STRIP_ALL, relocation info need
556a85fe12eSEd Maste 		 * to be stripped. Skip filtering otherwisw.
557a85fe12eSEd Maste 		 */
558a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL &&
559a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
560a85fe12eSEd Maste 			filter_reloc(ecp, s);
561a85fe12eSEd Maste 
5623ef90571SEd Maste 		/*
5633ef90571SEd Maste 		 * The section indices in the SHT_GROUP section needs
5643ef90571SEd Maste 		 * to be updated since we might have stripped some
5653ef90571SEd Maste 		 * sections and changed section numbering.
5663ef90571SEd Maste 		 */
5673ef90571SEd Maste 		if (s->type == SHT_GROUP)
5683ef90571SEd Maste 			update_section_group(ecp, s);
5693ef90571SEd Maste 
570a85fe12eSEd Maste 		if (is_modify_section(ecp, s->name))
571a85fe12eSEd Maste 			modify_section(ecp, s);
572a85fe12eSEd Maste 
573a85fe12eSEd Maste 		copy_data(s);
574a85fe12eSEd Maste 
575a85fe12eSEd Maste 		/*
576a85fe12eSEd Maste 		 * If symbol table is modified, relocation info might
577a85fe12eSEd Maste 		 * need update, as symbol index may have changed.
578a85fe12eSEd Maste 		 */
579a85fe12eSEd Maste 		if ((ecp->flags & SYMTAB_INTACT) == 0 &&
580a85fe12eSEd Maste 		    (ecp->flags & SYMTAB_EXIST) &&
581a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
582a85fe12eSEd Maste 			update_reloc(ecp, s);
583a85fe12eSEd Maste 
584a85fe12eSEd Maste 		if (is_print_section(ecp, s->name))
585a85fe12eSEd Maste 			print_section(s);
586a85fe12eSEd Maste 	}
587a85fe12eSEd Maste }
588a85fe12eSEd Maste 
5893ef90571SEd Maste 
5903ef90571SEd Maste /*
5913ef90571SEd Maste  * Update section group section. The section indices in the SHT_GROUP
5923ef90571SEd Maste  * section need update after section numbering changed.
5933ef90571SEd Maste  */
5943ef90571SEd Maste static void
5953ef90571SEd Maste update_section_group(struct elfcopy *ecp, struct section *s)
5963ef90571SEd Maste {
5973ef90571SEd Maste 	GElf_Shdr	 ish;
5983ef90571SEd Maste 	Elf_Data	*id;
5993ef90571SEd Maste 	uint32_t	*ws, *wd;
6003ef90571SEd Maste 	uint64_t	 n;
6013ef90571SEd Maste 	size_t		 ishnum;
6023ef90571SEd Maste 	int		 i, j;
6033ef90571SEd Maste 
6043ef90571SEd Maste 	if (!elf_getshnum(ecp->ein, &ishnum))
6053ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getshnum failed: %s",
6063ef90571SEd Maste 		    elf_errmsg(-1));
6073ef90571SEd Maste 
6083ef90571SEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
6093ef90571SEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
6103ef90571SEd Maste 		    elf_errmsg(-1));
6113ef90571SEd Maste 
6123ef90571SEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
6133ef90571SEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
6143ef90571SEd Maste 		    elf_errmsg(-1));
6153ef90571SEd Maste 
6163ef90571SEd Maste 	if (ish.sh_size == 0)
6173ef90571SEd Maste 		return;
6183ef90571SEd Maste 
6193ef90571SEd Maste 	if (ish.sh_entsize == 0)
6203ef90571SEd Maste 		ish.sh_entsize = 4;
6213ef90571SEd Maste 
6223ef90571SEd Maste 	ws = id->d_buf;
6233ef90571SEd Maste 
6243ef90571SEd Maste 	/* We only support COMDAT section. */
6253ef90571SEd Maste #ifndef GRP_COMDAT
6263ef90571SEd Maste #define	GRP_COMDAT 0x1
6273ef90571SEd Maste #endif
6283ef90571SEd Maste 	if ((*ws & GRP_COMDAT) == 0)
6293ef90571SEd Maste 		return;
6303ef90571SEd Maste 
6313ef90571SEd Maste 	if ((s->buf = malloc(ish.sh_size)) == NULL)
6323ef90571SEd Maste 		err(EXIT_FAILURE, "malloc failed");
6333ef90571SEd Maste 
6343ef90571SEd Maste 	s->sz = ish.sh_size;
6353ef90571SEd Maste 
6363ef90571SEd Maste 	wd = s->buf;
6373ef90571SEd Maste 
6383ef90571SEd Maste 	/* Copy the flag word as-is. */
6393ef90571SEd Maste 	*wd = *ws;
6403ef90571SEd Maste 
6413ef90571SEd Maste 	/* Update the section indices. */
6423ef90571SEd Maste 	n = ish.sh_size / ish.sh_entsize;
6433ef90571SEd Maste 	for(i = 1, j = 1; (uint64_t)i < n; i++) {
6443ef90571SEd Maste 		if (ws[i] != SHN_UNDEF && ws[i] < ishnum &&
6453ef90571SEd Maste 		    ecp->secndx[ws[i]] != 0)
6463ef90571SEd Maste 			wd[j++] = ecp->secndx[ws[i]];
6473ef90571SEd Maste 		else
6483ef90571SEd Maste 			s->sz -= 4;
6493ef90571SEd Maste 	}
6503ef90571SEd Maste 
6513ef90571SEd Maste 	s->nocopy = 1;
6523ef90571SEd Maste }
6533ef90571SEd Maste 
654a85fe12eSEd Maste /*
655a85fe12eSEd Maste  * Filter relocation entries, only keep those entries whose
656a85fe12eSEd Maste  * symbol is in the keep list.
657a85fe12eSEd Maste  */
658a85fe12eSEd Maste static void
659a85fe12eSEd Maste filter_reloc(struct elfcopy *ecp, struct section *s)
660a85fe12eSEd Maste {
661a85fe12eSEd Maste 	const char	*name;
662a85fe12eSEd Maste 	GElf_Shdr	 ish;
663a85fe12eSEd Maste 	GElf_Rel	 rel;
664a85fe12eSEd Maste 	GElf_Rela	 rela;
665a85fe12eSEd Maste 	Elf32_Rel	*rel32;
666a85fe12eSEd Maste 	Elf64_Rel	*rel64;
667a85fe12eSEd Maste 	Elf32_Rela	*rela32;
668a85fe12eSEd Maste 	Elf64_Rela	*rela64;
669a85fe12eSEd Maste 	Elf_Data	*id;
670a85fe12eSEd Maste 	uint64_t	 cap, n, nrels;
671a85fe12eSEd Maste 	int		 elferr, i;
672a85fe12eSEd Maste 
673a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
674a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
675a85fe12eSEd Maste 		    elf_errmsg(-1));
676a85fe12eSEd Maste 
677a85fe12eSEd Maste 	/* We don't want to touch relocation info for dynamic symbols. */
678a85fe12eSEd Maste 	if ((ecp->flags & SYMTAB_EXIST) == 0) {
679a85fe12eSEd Maste 		if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) {
680a85fe12eSEd Maste 			/*
681a85fe12eSEd Maste 			 * This reloc section applies to the symbol table
682a85fe12eSEd Maste 			 * that was stripped, so discard whole section.
683a85fe12eSEd Maste 			 */
684a85fe12eSEd Maste 			s->nocopy = 1;
685a85fe12eSEd Maste 			s->sz = 0;
686a85fe12eSEd Maste 		}
687a85fe12eSEd Maste 		return;
688a85fe12eSEd Maste 	} else {
689a85fe12eSEd Maste 		/* Symbol table exist, check if index equals. */
690a85fe12eSEd Maste 		if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
691a85fe12eSEd Maste 			return;
692a85fe12eSEd Maste 	}
693a85fe12eSEd Maste 
694a85fe12eSEd Maste #define	COPYREL(REL, SZ) do {					\
695a85fe12eSEd Maste 	if (nrels == 0) {					\
696a85fe12eSEd Maste 		if ((REL##SZ = malloc(cap *			\
697a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Rel))) == NULL)		\
698a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");	\
699a85fe12eSEd Maste 	}							\
700a85fe12eSEd Maste 	if (nrels >= cap) {					\
701a85fe12eSEd Maste 		cap *= 2;					\
702a85fe12eSEd Maste 		if ((REL##SZ = realloc(REL##SZ, cap *		\
703a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Rel))) == NULL)		\
704a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");	\
705a85fe12eSEd Maste 	}							\
706a85fe12eSEd Maste 	REL##SZ[nrels].r_offset = REL.r_offset;			\
707a85fe12eSEd Maste 	REL##SZ[nrels].r_info	= REL.r_info;			\
708a85fe12eSEd Maste 	if (s->type == SHT_RELA)				\
709a85fe12eSEd Maste 		rela##SZ[nrels].r_addend = rela.r_addend;	\
710a85fe12eSEd Maste 	nrels++;						\
711a85fe12eSEd Maste } while (0)
712a85fe12eSEd Maste 
713a85fe12eSEd Maste 	nrels = 0;
714a85fe12eSEd Maste 	cap = 4;		/* keep list is usually small. */
715a85fe12eSEd Maste 	rel32 = NULL;
716a85fe12eSEd Maste 	rel64 = NULL;
717a85fe12eSEd Maste 	rela32 = NULL;
718a85fe12eSEd Maste 	rela64 = NULL;
719a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
720a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
721a85fe12eSEd Maste 		    elf_errmsg(-1));
722a85fe12eSEd Maste 	n = ish.sh_size / ish.sh_entsize;
723a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
724a85fe12eSEd Maste 		if (s->type == SHT_REL) {
725a85fe12eSEd Maste 			if (gelf_getrel(id, i, &rel) != &rel)
726a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
727a85fe12eSEd Maste 				    elf_errmsg(-1));
728a85fe12eSEd Maste 		} else {
729a85fe12eSEd Maste 			if (gelf_getrela(id, i, &rela) != &rela)
730a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
731a85fe12eSEd Maste 				    elf_errmsg(-1));
732a85fe12eSEd Maste 		}
733a85fe12eSEd Maste 		name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
734a85fe12eSEd Maste 		    GELF_R_SYM(rel.r_info));
735a85fe12eSEd Maste 		if (name == NULL)
736a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
737a85fe12eSEd Maste 			    elf_errmsg(-1));
738a85fe12eSEd Maste 		if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) {
739a85fe12eSEd Maste 			if (ecp->oec == ELFCLASS32) {
740a85fe12eSEd Maste 				if (s->type == SHT_REL)
741a85fe12eSEd Maste 					COPYREL(rel, 32);
742a85fe12eSEd Maste 				else
743a85fe12eSEd Maste 					COPYREL(rela, 32);
744a85fe12eSEd Maste 			} else {
745a85fe12eSEd Maste 				if (s->type == SHT_REL)
746a85fe12eSEd Maste 					COPYREL(rel, 64);
747a85fe12eSEd Maste 				else
748a85fe12eSEd Maste 					COPYREL(rela, 64);
749a85fe12eSEd Maste 			}
750a85fe12eSEd Maste 		}
751a85fe12eSEd Maste 	}
752a85fe12eSEd Maste 	elferr = elf_errno();
753a85fe12eSEd Maste 	if (elferr != 0)
754a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
755a85fe12eSEd Maste 		    elf_errmsg(elferr));
756a85fe12eSEd Maste 
757a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32) {
758a85fe12eSEd Maste 		if (s->type == SHT_REL)
759a85fe12eSEd Maste 			s->buf = rel32;
760a85fe12eSEd Maste 		else
761a85fe12eSEd Maste 			s->buf = rela32;
762a85fe12eSEd Maste 	} else {
763a85fe12eSEd Maste 		if (s->type == SHT_REL)
764a85fe12eSEd Maste 			s->buf = rel64;
765a85fe12eSEd Maste 		else
766a85fe12eSEd Maste 			s->buf = rela64;
767a85fe12eSEd Maste 	}
768a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
769a85fe12eSEd Maste 	    ELF_T_RELA), nrels, EV_CURRENT);
770a85fe12eSEd Maste 	s->nocopy = 1;
771a85fe12eSEd Maste }
772a85fe12eSEd Maste 
773a85fe12eSEd Maste static void
774a85fe12eSEd Maste update_reloc(struct elfcopy *ecp, struct section *s)
775a85fe12eSEd Maste {
776a85fe12eSEd Maste 	GElf_Shdr	 osh;
777a85fe12eSEd Maste 	GElf_Rel	 rel;
778a85fe12eSEd Maste 	GElf_Rela	 rela;
779a85fe12eSEd Maste 	Elf_Data	*od;
780a85fe12eSEd Maste 	uint64_t	 n;
781a85fe12eSEd Maste 	int		 i;
782a85fe12eSEd Maste 
783a85fe12eSEd Maste #define UPDATEREL(REL) do {						\
784a85fe12eSEd Maste 	if (gelf_get##REL(od, i, &REL) != &REL)				\
785a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_get##REL failed: %s",		\
786a85fe12eSEd Maste 		    elf_errmsg(-1));					\
787a85fe12eSEd Maste 	REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)],	\
788a85fe12eSEd Maste 	    GELF_R_TYPE(REL.r_info));					\
789a85fe12eSEd Maste 	if (!gelf_update_##REL(od, i, &REL))				\
790a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_##REL failed: %s",	\
791a85fe12eSEd Maste 		    elf_errmsg(-1));					\
792a85fe12eSEd Maste } while(0)
793a85fe12eSEd Maste 
794a85fe12eSEd Maste 	if (s->sz == 0)
795a85fe12eSEd Maste 		return;
796a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
797a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
798a85fe12eSEd Maste 		    elf_errmsg(-1));
799a85fe12eSEd Maste 	/* Only process .symtab reloc info. */
800a85fe12eSEd Maste 	if (osh.sh_link != elf_ndxscn(ecp->symtab->is))
801a85fe12eSEd Maste 		return;
802a85fe12eSEd Maste 	if ((od = elf_getdata(s->os, NULL)) == NULL)
803a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
804a85fe12eSEd Maste 		    elf_errmsg(-1));
805a85fe12eSEd Maste 	n = osh.sh_size / osh.sh_entsize;
806a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
807a85fe12eSEd Maste 		if (s->type == SHT_REL)
808a85fe12eSEd Maste 			UPDATEREL(rel);
809a85fe12eSEd Maste 		else
810a85fe12eSEd Maste 			UPDATEREL(rela);
811a85fe12eSEd Maste 	}
812a85fe12eSEd Maste }
813a85fe12eSEd Maste 
814a85fe12eSEd Maste static void
815a85fe12eSEd Maste pad_section(struct elfcopy *ecp, struct section *s)
816a85fe12eSEd Maste {
817a85fe12eSEd Maste 	GElf_Shdr	 osh;
818a85fe12eSEd Maste 	Elf_Data	*od;
819a85fe12eSEd Maste 
820a85fe12eSEd Maste 	if (s == NULL || s->pad_sz == 0)
821a85fe12eSEd Maste 		return;
822a85fe12eSEd Maste 
823a85fe12eSEd Maste 	if ((s->pad = malloc(s->pad_sz)) == NULL)
824a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
825a85fe12eSEd Maste 	memset(s->pad, ecp->fill, s->pad_sz);
826a85fe12eSEd Maste 
827a85fe12eSEd Maste 	/* Create a new Elf_Data to contain the padding bytes. */
828a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
829a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
830a85fe12eSEd Maste 		    elf_errmsg(-1));
831a85fe12eSEd Maste 	od->d_align = 1;
832a85fe12eSEd Maste 	od->d_off = s->sz;
833a85fe12eSEd Maste 	od->d_buf = s->pad;
834a85fe12eSEd Maste 	od->d_type = ELF_T_BYTE;
835a85fe12eSEd Maste 	od->d_size = s->pad_sz;
836a85fe12eSEd Maste 	od->d_version = EV_CURRENT;
837a85fe12eSEd Maste 
838a85fe12eSEd Maste 	/* Update section header. */
839a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
840a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
841a85fe12eSEd Maste 		    elf_errmsg(-1));
842a85fe12eSEd Maste 	osh.sh_size = s->sz + s->pad_sz;
843a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
844a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
845a85fe12eSEd Maste 		    elf_errmsg(-1));
846a85fe12eSEd Maste }
847a85fe12eSEd Maste 
848a85fe12eSEd Maste void
849a85fe12eSEd Maste resync_sections(struct elfcopy *ecp)
850a85fe12eSEd Maste {
851a85fe12eSEd Maste 	struct section	*s, *ps;
852a85fe12eSEd Maste 	GElf_Shdr	 osh;
853a85fe12eSEd Maste 	uint64_t	 off;
854a85fe12eSEd Maste 	int		 first;
855a85fe12eSEd Maste 
856a85fe12eSEd Maste 	ps = NULL;
857a85fe12eSEd Maste 	first = 1;
858a85fe12eSEd Maste 	off = 0;
859a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
860a85fe12eSEd Maste 		if (first) {
861a85fe12eSEd Maste 			off = s->off;
862a85fe12eSEd Maste 			first = 0;
863a85fe12eSEd Maste 		}
864a85fe12eSEd Maste 
8654a85c691SEd Maste 		/*
8664a85c691SEd Maste 		 * Ignore TLS sections with load address 0 and without
8674a85c691SEd Maste 		 * content. We don't need to adjust their file offset or
8684a85c691SEd Maste 		 * VMA, only the size matters.
8694a85c691SEd Maste 		 */
8704a85c691SEd Maste 		if (s->seg_tls != NULL && s->type == SHT_NOBITS &&
8714a85c691SEd Maste 		    s->off == 0)
8724a85c691SEd Maste 			continue;
8734a85c691SEd Maste 
874a85fe12eSEd Maste 		/* Align section offset. */
8752b39d4f6SEd Maste 		if (s->align == 0)
8762b39d4f6SEd Maste 			s->align = 1;
877a85fe12eSEd Maste 		if (off <= s->off) {
878a85fe12eSEd Maste 			if (!s->loadable)
879a85fe12eSEd Maste 				s->off = roundup(off, s->align);
880a85fe12eSEd Maste 		} else {
881a85fe12eSEd Maste 			if (s->loadable)
88217eee522SEd Maste 				warnx("moving loadable section %s, "
88317eee522SEd Maste 				    "is this intentional?", s->name);
884a85fe12eSEd Maste 			s->off = roundup(off, s->align);
885a85fe12eSEd Maste 		}
886a85fe12eSEd Maste 
887a85fe12eSEd Maste 		/* Calculate next section offset. */
888a85fe12eSEd Maste 		off = s->off;
889a85fe12eSEd Maste 		if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))
890a85fe12eSEd Maste 			off += s->sz;
891a85fe12eSEd Maste 
892a85fe12eSEd Maste 		if (s->pseudo) {
893a85fe12eSEd Maste 			ps = NULL;
894a85fe12eSEd Maste 			continue;
895a85fe12eSEd Maste 		}
896a85fe12eSEd Maste 
897a85fe12eSEd Maste 		/* Count padding bytes added through --pad-to. */
898a85fe12eSEd Maste 		if (s->pad_sz > 0)
899a85fe12eSEd Maste 			off += s->pad_sz;
900a85fe12eSEd Maste 
901a85fe12eSEd Maste 		/* Update section header accordingly. */
902a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
903a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
904a85fe12eSEd Maste 			    elf_errmsg(-1));
905a85fe12eSEd Maste 		osh.sh_addr = s->vma;
906a85fe12eSEd Maste 		osh.sh_offset = s->off;
907a85fe12eSEd Maste 		osh.sh_size = s->sz;
908a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
909a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
910a85fe12eSEd Maste 			    elf_errmsg(-1));
911a85fe12eSEd Maste 
912a85fe12eSEd Maste 		/* Add padding for previous section, if need. */
913a85fe12eSEd Maste 		if (ps != NULL) {
914a85fe12eSEd Maste 			if (ps->pad_sz > 0) {
915a85fe12eSEd Maste 				/* Apply padding added by --pad-to. */
916a85fe12eSEd Maste 				pad_section(ecp, ps);
917a85fe12eSEd Maste 			} else if ((ecp->flags & GAP_FILL) &&
918a85fe12eSEd Maste 			    (ps->off + ps->sz < s->off)) {
919a85fe12eSEd Maste 				/*
920a85fe12eSEd Maste 				 * Fill the gap between sections by padding
921a85fe12eSEd Maste 				 * the section with lower address.
922a85fe12eSEd Maste 				 */
923a85fe12eSEd Maste 				ps->pad_sz = s->off - (ps->off + ps->sz);
924a85fe12eSEd Maste 				pad_section(ecp, ps);
925a85fe12eSEd Maste 			}
926a85fe12eSEd Maste 		}
927a85fe12eSEd Maste 
928a85fe12eSEd Maste 		ps = s;
929a85fe12eSEd Maste 	}
930a85fe12eSEd Maste 
931a85fe12eSEd Maste 	/* Pad the last section, if need. */
932a85fe12eSEd Maste 	if (ps != NULL && ps->pad_sz > 0)
933a85fe12eSEd Maste 		pad_section(ecp, ps);
934a85fe12eSEd Maste }
935a85fe12eSEd Maste 
936a85fe12eSEd Maste static void
937a85fe12eSEd Maste modify_section(struct elfcopy *ecp, struct section *s)
938a85fe12eSEd Maste {
939a85fe12eSEd Maste 	struct sec_action	*sac;
940a85fe12eSEd Maste 	size_t			 srcsz, dstsz, p, len;
941a85fe12eSEd Maste 	char			*b, *c, *d, *src, *end;
942a85fe12eSEd Maste 	int			 dupe;
943a85fe12eSEd Maste 
944a85fe12eSEd Maste 	src = read_section(s, &srcsz);
945a85fe12eSEd Maste 	if (src == NULL || srcsz == 0) {
946a85fe12eSEd Maste 		/* For empty section, we proceed if we need to append. */
947a85fe12eSEd Maste 		if (!is_append_section(ecp, s->name))
948a85fe12eSEd Maste 			return;
949a85fe12eSEd Maste 	}
950a85fe12eSEd Maste 
951a85fe12eSEd Maste 	/* Allocate buffer needed for new section data. */
952a85fe12eSEd Maste 	dstsz = srcsz;
953a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
954a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
955a85fe12eSEd Maste 		dstsz += strlen(sac->string) + 1;
956a85fe12eSEd Maste 	}
957a85fe12eSEd Maste 	if ((b = malloc(dstsz)) == NULL)
958a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
959a85fe12eSEd Maste 	s->buf = b;
960a85fe12eSEd Maste 
961a85fe12eSEd Maste 	/* Compress section. */
962a85fe12eSEd Maste 	p = 0;
963a85fe12eSEd Maste 	if (is_compress_section(ecp, s->name)) {
964a85fe12eSEd Maste 		end = src + srcsz;
965a85fe12eSEd Maste 		for(c = src; c < end;) {
966a85fe12eSEd Maste 			len = 0;
967a85fe12eSEd Maste 			while(c + len < end && c[len] != '\0')
968a85fe12eSEd Maste 				len++;
969a85fe12eSEd Maste 			if (c + len == end) {
970a85fe12eSEd Maste 				/* XXX should we warn here? */
971a85fe12eSEd Maste 				strncpy(&b[p], c, len);
972a85fe12eSEd Maste 				p += len;
973a85fe12eSEd Maste 				break;
974a85fe12eSEd Maste 			}
975a85fe12eSEd Maste 			dupe = 0;
976a85fe12eSEd Maste 			for (d = b; d < b + p; ) {
977a85fe12eSEd Maste 				if (strcmp(d, c) == 0) {
978a85fe12eSEd Maste 					dupe = 1;
979a85fe12eSEd Maste 					break;
980a85fe12eSEd Maste 				}
981a85fe12eSEd Maste 				d += strlen(d) + 1;
982a85fe12eSEd Maste 			}
983a85fe12eSEd Maste 			if (!dupe) {
984a85fe12eSEd Maste 				strncpy(&b[p], c, len);
985a85fe12eSEd Maste 				b[p + len] = '\0';
986a85fe12eSEd Maste 				p += len + 1;
987a85fe12eSEd Maste 			}
988a85fe12eSEd Maste 			c += len + 1;
989a85fe12eSEd Maste 		}
990a85fe12eSEd Maste 	} else {
991a85fe12eSEd Maste 		memcpy(b, src, srcsz);
992a85fe12eSEd Maste 		p += srcsz;
993a85fe12eSEd Maste 	}
994a85fe12eSEd Maste 
995a85fe12eSEd Maste 	/* Append section. */
996a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
997a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
998a85fe12eSEd Maste 		len = strlen(sac->string);
999a85fe12eSEd Maste 		strncpy(&b[p], sac->string, len);
1000a85fe12eSEd Maste 		b[p + len] = '\0';
1001a85fe12eSEd Maste 		p += len + 1;
1002a85fe12eSEd Maste 	}
1003a85fe12eSEd Maste 
1004a85fe12eSEd Maste 	s->sz = p;
1005a85fe12eSEd Maste 	s->nocopy = 1;
1006a85fe12eSEd Maste }
1007a85fe12eSEd Maste 
1008a85fe12eSEd Maste static void
1009a85fe12eSEd Maste print_data(const char *d, size_t sz)
1010a85fe12eSEd Maste {
1011a85fe12eSEd Maste 	const char *c;
1012a85fe12eSEd Maste 
1013a85fe12eSEd Maste 	for (c = d; c < d + sz; c++) {
1014a85fe12eSEd Maste 		if (*c == '\0')
1015a85fe12eSEd Maste 			putchar('\n');
1016a85fe12eSEd Maste 		else
1017a85fe12eSEd Maste 			putchar(*c);
1018a85fe12eSEd Maste 	}
1019a85fe12eSEd Maste }
1020a85fe12eSEd Maste 
1021a85fe12eSEd Maste static void
1022a85fe12eSEd Maste print_section(struct section *s)
1023a85fe12eSEd Maste {
1024a85fe12eSEd Maste 	Elf_Data	*id;
1025a85fe12eSEd Maste 	int		 elferr;
1026a85fe12eSEd Maste 
1027a85fe12eSEd Maste 	if (s->buf != NULL && s->sz > 0) {
1028a85fe12eSEd Maste 		print_data(s->buf, s->sz);
1029a85fe12eSEd Maste 	} else {
1030a85fe12eSEd Maste 		id = NULL;
1031a85fe12eSEd Maste 		while ((id = elf_getdata(s->is, id)) != NULL)
1032a85fe12eSEd Maste 			print_data(id->d_buf, id->d_size);
1033a85fe12eSEd Maste 		elferr = elf_errno();
1034a85fe12eSEd Maste 		if (elferr != 0)
1035a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1036a85fe12eSEd Maste 			    elf_errmsg(elferr));
1037a85fe12eSEd Maste 	}
1038a85fe12eSEd Maste 	putchar('\n');
1039a85fe12eSEd Maste }
1040a85fe12eSEd Maste 
1041a85fe12eSEd Maste static void *
1042a85fe12eSEd Maste read_section(struct section *s, size_t *size)
1043a85fe12eSEd Maste {
1044a85fe12eSEd Maste 	Elf_Data	*id;
1045a85fe12eSEd Maste 	char		*b;
1046a85fe12eSEd Maste 	size_t		 sz;
1047a85fe12eSEd Maste 	int		 elferr;
1048a85fe12eSEd Maste 
1049a85fe12eSEd Maste 	sz = 0;
1050a85fe12eSEd Maste 	b = NULL;
1051a85fe12eSEd Maste 	id = NULL;
1052a85fe12eSEd Maste 	while ((id = elf_getdata(s->is, id)) != NULL) {
1053a85fe12eSEd Maste 		if (b == NULL)
1054a85fe12eSEd Maste 			b = malloc(id->d_size);
1055a85fe12eSEd Maste 		else
1056a85fe12eSEd Maste 			b = malloc(sz + id->d_size);
1057a85fe12eSEd Maste 		if (b == NULL)
1058a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc or realloc failed");
1059a85fe12eSEd Maste 
1060a85fe12eSEd Maste 		memcpy(&b[sz], id->d_buf, id->d_size);
1061a85fe12eSEd Maste 		sz += id->d_size;
1062a85fe12eSEd Maste 	}
1063a85fe12eSEd Maste 	elferr = elf_errno();
1064a85fe12eSEd Maste 	if (elferr != 0)
1065a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1066a85fe12eSEd Maste 		    elf_errmsg(elferr));
1067a85fe12eSEd Maste 
1068a85fe12eSEd Maste 	*size = sz;
1069a85fe12eSEd Maste 
1070a85fe12eSEd Maste 	return (b);
1071a85fe12eSEd Maste }
1072a85fe12eSEd Maste 
1073a85fe12eSEd Maste void
1074a85fe12eSEd Maste copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,
1075a85fe12eSEd Maste     int sec_flags)
1076a85fe12eSEd Maste {
1077a85fe12eSEd Maste 	GElf_Shdr ish, osh;
1078a85fe12eSEd Maste 
1079a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
1080a85fe12eSEd Maste 		errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s",
1081a85fe12eSEd Maste 		    elf_errmsg(-1));
1082a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
1083a85fe12eSEd Maste 		errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s",
1084a85fe12eSEd Maste 		    elf_errmsg(-1));
1085a85fe12eSEd Maste 
1086a85fe12eSEd Maste 	if (copy)
1087a85fe12eSEd Maste 		(void) memcpy(&osh, &ish, sizeof(ish));
1088a85fe12eSEd Maste 	else {
1089a85fe12eSEd Maste 		osh.sh_type		= s->type;
1090a85fe12eSEd Maste 		osh.sh_addr		= s->vma;
1091a85fe12eSEd Maste 		osh.sh_offset		= s->off;
1092a85fe12eSEd Maste 		osh.sh_size		= s->sz;
1093a85fe12eSEd Maste 		osh.sh_link		= ish.sh_link;
1094a85fe12eSEd Maste 		osh.sh_info		= ish.sh_info;
1095a85fe12eSEd Maste 		osh.sh_addralign	= s->align;
1096a85fe12eSEd Maste 		osh.sh_entsize		= ish.sh_entsize;
1097a85fe12eSEd Maste 
1098a85fe12eSEd Maste 		if (sec_flags) {
1099a85fe12eSEd Maste 			osh.sh_flags = 0;
1100a85fe12eSEd Maste 			if (sec_flags & SF_ALLOC) {
1101a85fe12eSEd Maste 				osh.sh_flags |= SHF_ALLOC;
1102a85fe12eSEd Maste 				if (!s->loadable)
1103a85fe12eSEd Maste 					warnx("set SHF_ALLOC flag for "
1104a85fe12eSEd Maste 					    "unloadable section %s",
1105a85fe12eSEd Maste 					    s->name);
1106a85fe12eSEd Maste 			}
1107a85fe12eSEd Maste 			if ((sec_flags & SF_READONLY) == 0)
1108a85fe12eSEd Maste 				osh.sh_flags |= SHF_WRITE;
1109a85fe12eSEd Maste 			if (sec_flags & SF_CODE)
1110a85fe12eSEd Maste 				osh.sh_flags |= SHF_EXECINSTR;
11113ef90571SEd Maste 		} else {
1112a85fe12eSEd Maste 			osh.sh_flags = ish.sh_flags;
11133ef90571SEd Maste 			if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
11143ef90571SEd Maste 				osh.sh_flags |= SHF_INFO_LINK;
11153ef90571SEd Maste 		}
1116a85fe12eSEd Maste 	}
1117a85fe12eSEd Maste 
1118a85fe12eSEd Maste 	if (name == NULL)
1119a85fe12eSEd Maste 		add_to_shstrtab(ecp, s->name);
1120a85fe12eSEd Maste 	else
1121a85fe12eSEd Maste 		add_to_shstrtab(ecp, name);
1122a85fe12eSEd Maste 
1123a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
1124a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1125a85fe12eSEd Maste 		    elf_errmsg(-1));
1126a85fe12eSEd Maste }
1127a85fe12eSEd Maste 
1128a85fe12eSEd Maste void
1129a85fe12eSEd Maste copy_data(struct section *s)
1130a85fe12eSEd Maste {
1131a85fe12eSEd Maste 	Elf_Data	*id, *od;
1132a85fe12eSEd Maste 	int		 elferr;
1133a85fe12eSEd Maste 
1134a85fe12eSEd Maste 	if (s->nocopy && s->buf == NULL)
1135a85fe12eSEd Maste 		return;
1136a85fe12eSEd Maste 
1137a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL) {
1138a85fe12eSEd Maste 		elferr = elf_errno();
1139a85fe12eSEd Maste 		if (elferr != 0)
1140a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1141a85fe12eSEd Maste 			    elf_errmsg(elferr));
1142a85fe12eSEd Maste 		return;
1143a85fe12eSEd Maste 	}
1144a85fe12eSEd Maste 
1145a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
1146a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1147a85fe12eSEd Maste 		    elf_errmsg(-1));
1148a85fe12eSEd Maste 
1149a85fe12eSEd Maste 	if (s->nocopy) {
1150a85fe12eSEd Maste 		/* Use s->buf as content if s->nocopy is set. */
1151a85fe12eSEd Maste 		od->d_align	= id->d_align;
1152a85fe12eSEd Maste 		od->d_off	= 0;
1153a85fe12eSEd Maste 		od->d_buf	= s->buf;
1154a85fe12eSEd Maste 		od->d_type	= id->d_type;
1155a85fe12eSEd Maste 		od->d_size	= s->sz;
1156a85fe12eSEd Maste 		od->d_version	= id->d_version;
1157a85fe12eSEd Maste 	} else {
1158a85fe12eSEd Maste 		od->d_align	= id->d_align;
1159a85fe12eSEd Maste 		od->d_off	= id->d_off;
1160a85fe12eSEd Maste 		od->d_buf	= id->d_buf;
1161a85fe12eSEd Maste 		od->d_type	= id->d_type;
1162a85fe12eSEd Maste 		od->d_size	= id->d_size;
1163a85fe12eSEd Maste 		od->d_version	= id->d_version;
1164a85fe12eSEd Maste 	}
11654a85c691SEd Maste 
11664a85c691SEd Maste 	/*
11674a85c691SEd Maste 	 * Alignment Fixup. libelf does not allow the alignment for
11684a85c691SEd Maste 	 * Elf_Data descriptor to be set to 0. In this case we workaround
11694a85c691SEd Maste 	 * it by setting the alignment to 1.
11704a85c691SEd Maste 	 *
11714a85c691SEd Maste 	 * According to the ELF ABI, alignment 0 and 1 has the same
11724a85c691SEd Maste 	 * meaning: the section has no alignment constraints.
11734a85c691SEd Maste 	 */
11744a85c691SEd Maste 	if (od->d_align == 0)
11754a85c691SEd Maste 		od->d_align = 1;
1176a85fe12eSEd Maste }
1177a85fe12eSEd Maste 
1178a85fe12eSEd Maste struct section *
1179a85fe12eSEd Maste create_external_section(struct elfcopy *ecp, const char *name, char *newname,
1180a85fe12eSEd Maste     void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,
1181a85fe12eSEd Maste     uint64_t flags, uint64_t align, uint64_t vma, int loadable)
1182a85fe12eSEd Maste {
1183a85fe12eSEd Maste 	struct section	*s;
1184a85fe12eSEd Maste 	Elf_Scn		*os;
1185a85fe12eSEd Maste 	Elf_Data	*od;
1186a85fe12eSEd Maste 	GElf_Shdr	 osh;
1187a85fe12eSEd Maste 
1188a85fe12eSEd Maste 	if ((os = elf_newscn(ecp->eout)) == NULL)
1189a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn() failed: %s",
1190a85fe12eSEd Maste 		    elf_errmsg(-1));
1191a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1192a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1193a85fe12eSEd Maste 	s->name = name;
1194a85fe12eSEd Maste 	s->newname = newname;	/* needs to be free()'ed */
1195a85fe12eSEd Maste 	s->off = off;
1196a85fe12eSEd Maste 	s->sz = size;
1197a85fe12eSEd Maste 	s->vma = vma;
1198a85fe12eSEd Maste 	s->align = align;
1199a85fe12eSEd Maste 	s->loadable = loadable;
1200a85fe12eSEd Maste 	s->is = NULL;
1201a85fe12eSEd Maste 	s->os = os;
1202a85fe12eSEd Maste 	s->type = stype;
1203a85fe12eSEd Maste 	s->nocopy = 1;
1204a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 1);
1205a85fe12eSEd Maste 
1206a85fe12eSEd Maste 	if (gelf_getshdr(os, &osh) == NULL)
1207a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1208a85fe12eSEd Maste 		    elf_errmsg(-1));
1209a85fe12eSEd Maste 	osh.sh_flags = flags;
1210a85fe12eSEd Maste 	osh.sh_type = s->type;
1211a85fe12eSEd Maste 	osh.sh_addr = s->vma;
1212a85fe12eSEd Maste 	osh.sh_addralign = s->align;
1213a85fe12eSEd Maste 	if (!gelf_update_shdr(os, &osh))
1214a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1215a85fe12eSEd Maste 		    elf_errmsg(-1));
1216a85fe12eSEd Maste 	add_to_shstrtab(ecp, name);
1217a85fe12eSEd Maste 
1218a85fe12eSEd Maste 	if (buf != NULL && size != 0) {
1219a85fe12eSEd Maste 		if ((od = elf_newdata(os)) == NULL)
1220a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1221a85fe12eSEd Maste 			    elf_errmsg(-1));
1222a85fe12eSEd Maste 		od->d_align = align;
1223a85fe12eSEd Maste 		od->d_off = 0;
1224a85fe12eSEd Maste 		od->d_buf = buf;
1225a85fe12eSEd Maste 		od->d_size = size;
1226a85fe12eSEd Maste 		od->d_type = dtype;
1227a85fe12eSEd Maste 		od->d_version = EV_CURRENT;
1228a85fe12eSEd Maste 	}
1229a85fe12eSEd Maste 
1230a85fe12eSEd Maste 	/*
1231a85fe12eSEd Maste 	 * Clear SYMTAB_INTACT, as we probably need to update/add new
1232a85fe12eSEd Maste 	 * STT_SECTION symbols into the symbol table.
1233a85fe12eSEd Maste 	 */
1234a85fe12eSEd Maste 	ecp->flags &= ~SYMTAB_INTACT;
1235a85fe12eSEd Maste 
1236a85fe12eSEd Maste 	return (s);
1237a85fe12eSEd Maste }
1238a85fe12eSEd Maste 
1239a85fe12eSEd Maste /*
1240a85fe12eSEd Maste  * Insert sections specified by --add-section to the end of section list.
1241a85fe12eSEd Maste  */
1242a85fe12eSEd Maste static void
1243a85fe12eSEd Maste insert_sections(struct elfcopy *ecp)
1244a85fe12eSEd Maste {
1245a85fe12eSEd Maste 	struct sec_add	*sa;
1246a85fe12eSEd Maste 	struct section	*s;
1247a85fe12eSEd Maste 	size_t		 off;
1248a85fe12eSEd Maste 
1249a85fe12eSEd Maste 	/* Put these sections in the end of current list. */
1250a85fe12eSEd Maste 	off = 0;
1251a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1252a85fe12eSEd Maste 		if (s->type != SHT_NOBITS && s->type != SHT_NULL)
1253a85fe12eSEd Maste 			off = s->off + s->sz;
1254a85fe12eSEd Maste 		else
1255a85fe12eSEd Maste 			off = s->off;
1256a85fe12eSEd Maste 	}
1257a85fe12eSEd Maste 
1258a85fe12eSEd Maste 	STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {
1259a85fe12eSEd Maste 
1260a85fe12eSEd Maste 		/* TODO: Add section header vma/lma, flag changes here */
1261a85fe12eSEd Maste 
1262a85fe12eSEd Maste 		(void) create_external_section(ecp, sa->name, NULL, sa->content,
1263a85fe12eSEd Maste 		    sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0);
1264a85fe12eSEd Maste 	}
1265a85fe12eSEd Maste }
1266a85fe12eSEd Maste 
1267a85fe12eSEd Maste void
1268a85fe12eSEd Maste add_to_shstrtab(struct elfcopy *ecp, const char *name)
1269a85fe12eSEd Maste {
1270a85fe12eSEd Maste 	struct section *s;
1271a85fe12eSEd Maste 
1272a85fe12eSEd Maste 	s = ecp->shstrtab;
1273a85fe12eSEd Maste 	insert_to_strtab(s, name);
1274a85fe12eSEd Maste }
1275a85fe12eSEd Maste 
1276a85fe12eSEd Maste void
1277a85fe12eSEd Maste update_shdr(struct elfcopy *ecp, int update_link)
1278a85fe12eSEd Maste {
1279a85fe12eSEd Maste 	struct section	*s;
1280a85fe12eSEd Maste 	GElf_Shdr	 osh;
1281a85fe12eSEd Maste 	int		 elferr;
1282a85fe12eSEd Maste 
1283a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1284a85fe12eSEd Maste 		if (s->pseudo)
1285a85fe12eSEd Maste 			continue;
1286a85fe12eSEd Maste 
1287a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
1288a85fe12eSEd Maste 			errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s",
1289a85fe12eSEd Maste 			    elf_errmsg(-1));
1290a85fe12eSEd Maste 
1291a85fe12eSEd Maste 		/* Find section name in string table and set sh_name. */
1292a85fe12eSEd Maste 		osh.sh_name = lookup_string(ecp->shstrtab, s->name);
1293a85fe12eSEd Maste 
1294a85fe12eSEd Maste 		/*
1295a85fe12eSEd Maste 		 * sh_link needs to be updated, since the index of the
1296a85fe12eSEd Maste 		 * linked section might have changed.
1297a85fe12eSEd Maste 		 */
1298a85fe12eSEd Maste 		if (update_link && osh.sh_link != 0)
1299a85fe12eSEd Maste 			osh.sh_link = ecp->secndx[osh.sh_link];
1300a85fe12eSEd Maste 
1301a85fe12eSEd Maste 		/*
1302a85fe12eSEd Maste 		 * sh_info of relocation section links to the section to which
1303a85fe12eSEd Maste 		 * its relocation info applies. So it may need update as well.
1304a85fe12eSEd Maste 		 */
1305a85fe12eSEd Maste 		if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1306a85fe12eSEd Maste 		    osh.sh_info != 0)
1307a85fe12eSEd Maste 			osh.sh_info = ecp->secndx[osh.sh_info];
1308a85fe12eSEd Maste 
1309b00fe64fSEd Maste 		/*
1310b00fe64fSEd Maste 		 * sh_info of SHT_GROUP section needs to point to the correct
1311b00fe64fSEd Maste 		 * string in the symbol table.
1312b00fe64fSEd Maste 		 */
1313b00fe64fSEd Maste 		if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&
1314b00fe64fSEd Maste 		    (ecp->flags & SYMTAB_INTACT) == 0)
1315b00fe64fSEd Maste 			osh.sh_info = ecp->symndx[osh.sh_info];
1316b00fe64fSEd Maste 
1317a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
1318a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1319a85fe12eSEd Maste 			    elf_errmsg(-1));
1320a85fe12eSEd Maste 	}
1321a85fe12eSEd Maste 	elferr = elf_errno();
1322a85fe12eSEd Maste 	if (elferr != 0)
1323a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
1324a85fe12eSEd Maste 		    elf_errmsg(elferr));
1325a85fe12eSEd Maste }
1326a85fe12eSEd Maste 
1327a85fe12eSEd Maste void
1328a85fe12eSEd Maste init_shstrtab(struct elfcopy *ecp)
1329a85fe12eSEd Maste {
1330a85fe12eSEd Maste 	struct section *s;
1331a85fe12eSEd Maste 
1332a85fe12eSEd Maste 	if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
1333a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1334a85fe12eSEd Maste 	s = ecp->shstrtab;
1335a85fe12eSEd Maste 	s->name = ".shstrtab";
1336a85fe12eSEd Maste 	s->is = NULL;
1337a85fe12eSEd Maste 	s->sz = 0;
1338a85fe12eSEd Maste 	s->align = 1;
1339a85fe12eSEd Maste 	s->loadable = 0;
1340a85fe12eSEd Maste 	s->type = SHT_STRTAB;
1341a85fe12eSEd Maste 	s->vma = 0;
13429ef62fdbSEd Maste 
13439ef62fdbSEd Maste 	insert_to_strtab(s, "");
13449ef62fdbSEd Maste 	insert_to_strtab(s, ".symtab");
13459ef62fdbSEd Maste 	insert_to_strtab(s, ".strtab");
13469ef62fdbSEd Maste 	insert_to_strtab(s, ".shstrtab");
1347a85fe12eSEd Maste }
1348a85fe12eSEd Maste 
1349a85fe12eSEd Maste void
1350a85fe12eSEd Maste set_shstrtab(struct elfcopy *ecp)
1351a85fe12eSEd Maste {
1352a85fe12eSEd Maste 	struct section	*s;
1353a85fe12eSEd Maste 	Elf_Data	*data;
1354a85fe12eSEd Maste 	GElf_Shdr	 sh;
1355a85fe12eSEd Maste 
1356a85fe12eSEd Maste 	s = ecp->shstrtab;
1357a85fe12eSEd Maste 
1358619ba3b4SEd Maste 	if (s->os == NULL) {
1359619ba3b4SEd Maste 		/* Input object does not contain .shstrtab section */
1360619ba3b4SEd Maste 		if ((s->os = elf_newscn(ecp->eout)) == NULL)
1361619ba3b4SEd Maste 			errx(EXIT_FAILURE, "elf_newscn failed: %s",
1362619ba3b4SEd Maste 			    elf_errmsg(-1));
1363619ba3b4SEd Maste 		insert_to_sec_list(ecp, s, 1);
1364619ba3b4SEd Maste 	}
1365619ba3b4SEd Maste 
1366a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &sh) == NULL)
1367a85fe12eSEd Maste 		errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s",
1368a85fe12eSEd Maste 		    elf_errmsg(-1));
1369a85fe12eSEd Maste 	sh.sh_addr	= 0;
1370a85fe12eSEd Maste 	sh.sh_addralign	= 1;
1371a85fe12eSEd Maste 	sh.sh_offset	= s->off;
1372a85fe12eSEd Maste 	sh.sh_type	= SHT_STRTAB;
1373a85fe12eSEd Maste 	sh.sh_flags	= 0;
1374a85fe12eSEd Maste 	sh.sh_entsize	= 0;
1375a85fe12eSEd Maste 	sh.sh_info	= 0;
1376a85fe12eSEd Maste 	sh.sh_link	= 0;
1377a85fe12eSEd Maste 
1378a85fe12eSEd Maste 	if ((data = elf_newdata(s->os)) == NULL)
1379a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1380a85fe12eSEd Maste 		    elf_errmsg(-1));
1381a85fe12eSEd Maste 
1382a85fe12eSEd Maste 	/*
1383a85fe12eSEd Maste 	 * If we don't have a symbol table, skip those a few bytes
1384a85fe12eSEd Maste 	 * which are reserved for this in the beginning of shstrtab.
1385a85fe12eSEd Maste 	 */
1386a85fe12eSEd Maste 	if (!(ecp->flags & SYMTAB_EXIST)) {
1387a85fe12eSEd Maste 		s->sz -= sizeof(".symtab\0.strtab");
1388a85fe12eSEd Maste 		memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"),
1389a85fe12eSEd Maste 		    s->sz);
1390a85fe12eSEd Maste 	}
1391a85fe12eSEd Maste 
1392a85fe12eSEd Maste 	sh.sh_size	= s->sz;
1393a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &sh))
1394a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1395a85fe12eSEd Maste 		    elf_errmsg(-1));
1396a85fe12eSEd Maste 
1397a85fe12eSEd Maste 	data->d_align	= 1;
1398a85fe12eSEd Maste 	data->d_buf	= s->buf;
1399a85fe12eSEd Maste 	data->d_size	= s->sz;
1400a85fe12eSEd Maste 	data->d_off	= 0;
1401a85fe12eSEd Maste 	data->d_type	= ELF_T_BYTE;
1402a85fe12eSEd Maste 	data->d_version	= EV_CURRENT;
1403a85fe12eSEd Maste 
1404a85fe12eSEd Maste 	if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))
1405a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",
1406a85fe12eSEd Maste 		     elf_errmsg(-1));
1407a85fe12eSEd Maste }
1408a85fe12eSEd Maste 
1409a85fe12eSEd Maste void
1410a85fe12eSEd Maste add_section(struct elfcopy *ecp, const char *arg)
1411a85fe12eSEd Maste {
1412a85fe12eSEd Maste 	struct sec_add	*sa;
1413a85fe12eSEd Maste 	struct stat	 sb;
1414a85fe12eSEd Maste 	const char	*s, *fn;
1415a85fe12eSEd Maste 	FILE		*fp;
1416a85fe12eSEd Maste 	int		 len;
1417a85fe12eSEd Maste 
1418a85fe12eSEd Maste 	if ((s = strchr(arg, '=')) == NULL)
1419a85fe12eSEd Maste 		errx(EXIT_FAILURE,
1420a85fe12eSEd Maste 		    "illegal format for --add-section option");
1421a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1422a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1423a85fe12eSEd Maste 
1424a85fe12eSEd Maste 	len = s - arg;
1425a85fe12eSEd Maste 	if ((sa->name = malloc(len + 1)) == NULL)
1426a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1427a85fe12eSEd Maste 	strncpy(sa->name, arg, len);
1428a85fe12eSEd Maste 	sa->name[len] = '\0';
1429a85fe12eSEd Maste 
1430a85fe12eSEd Maste 	fn = s + 1;
1431a85fe12eSEd Maste 	if (stat(fn, &sb) == -1)
1432a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1433a85fe12eSEd Maste 	sa->size = sb.st_size;
1434a85fe12eSEd Maste 	if ((sa->content = malloc(sa->size)) == NULL)
1435a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1436a85fe12eSEd Maste 	if ((fp = fopen(fn, "r")) == NULL)
1437a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", fn);
1438a85fe12eSEd Maste 	if (fread(sa->content, 1, sa->size, fp) == 0 ||
1439a85fe12eSEd Maste 	    ferror(fp))
1440a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1441a85fe12eSEd Maste 	fclose(fp);
1442a85fe12eSEd Maste 
1443a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1444a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1445a85fe12eSEd Maste }
1446a85fe12eSEd Maste 
1447a85fe12eSEd Maste void
1448a85fe12eSEd Maste free_sec_add(struct elfcopy *ecp)
1449a85fe12eSEd Maste {
1450a85fe12eSEd Maste 	struct sec_add *sa, *sa_temp;
1451a85fe12eSEd Maste 
1452a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {
1453a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);
1454a85fe12eSEd Maste 		free(sa->name);
1455a85fe12eSEd Maste 		free(sa->content);
1456a85fe12eSEd Maste 		free(sa);
1457a85fe12eSEd Maste 	}
1458a85fe12eSEd Maste }
1459a85fe12eSEd Maste 
1460a85fe12eSEd Maste static void
1461a85fe12eSEd Maste add_gnu_debuglink(struct elfcopy *ecp)
1462a85fe12eSEd Maste {
1463a85fe12eSEd Maste 	struct sec_add	*sa;
1464a85fe12eSEd Maste 	struct stat	 sb;
1465a85fe12eSEd Maste 	FILE		*fp;
1466a85fe12eSEd Maste 	char		*fnbase, *buf;
1467a85fe12eSEd Maste 	int		 crc_off;
1468a85fe12eSEd Maste 	int		 crc;
1469a85fe12eSEd Maste 
1470a85fe12eSEd Maste 	if (ecp->debuglink == NULL)
1471a85fe12eSEd Maste 		return;
1472a85fe12eSEd Maste 
1473a85fe12eSEd Maste 	/* Read debug file content. */
1474a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1475a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1476a85fe12eSEd Maste 	if ((sa->name = strdup(".gnu_debuglink")) == NULL)
1477a85fe12eSEd Maste 		err(EXIT_FAILURE, "strdup failed");
1478a85fe12eSEd Maste 	if (stat(ecp->debuglink, &sb) == -1)
1479a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1480a85fe12eSEd Maste 	if ((buf = malloc(sb.st_size)) == NULL)
1481a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1482a85fe12eSEd Maste 	if ((fp = fopen(ecp->debuglink, "r")) == NULL)
1483a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", ecp->debuglink);
1484a85fe12eSEd Maste 	if (fread(buf, 1, sb.st_size, fp) == 0 ||
1485a85fe12eSEd Maste 	    ferror(fp))
1486a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1487a85fe12eSEd Maste 	fclose(fp);
1488a85fe12eSEd Maste 
1489a85fe12eSEd Maste 	/* Calculate crc checksum.  */
1490a85fe12eSEd Maste 	crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);
1491a85fe12eSEd Maste 	free(buf);
1492a85fe12eSEd Maste 
1493a85fe12eSEd Maste 	/* Calculate section size and the offset to store crc checksum. */
1494a85fe12eSEd Maste 	if ((fnbase = basename(ecp->debuglink)) == NULL)
1495a85fe12eSEd Maste 		err(EXIT_FAILURE, "basename failed");
1496a85fe12eSEd Maste 	crc_off = roundup(strlen(fnbase) + 1, 4);
1497a85fe12eSEd Maste 	sa->size = crc_off + 4;
1498a85fe12eSEd Maste 
1499a85fe12eSEd Maste 	/* Section content. */
1500a85fe12eSEd Maste 	if ((sa->content = calloc(1, sa->size)) == NULL)
1501a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1502a85fe12eSEd Maste 	strncpy(sa->content, fnbase, strlen(fnbase));
1503a85fe12eSEd Maste 	if (ecp->oed == ELFDATA2LSB) {
1504a85fe12eSEd Maste 		sa->content[crc_off] = crc & 0xFF;
1505a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 8) & 0xFF;
1506a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 16) & 0xFF;
1507a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc >> 24;
1508a85fe12eSEd Maste 	} else {
1509a85fe12eSEd Maste 		sa->content[crc_off] = crc >> 24;
1510a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 16) & 0xFF;
1511a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 8) & 0xFF;
1512a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc & 0xFF;
1513a85fe12eSEd Maste 	}
1514a85fe12eSEd Maste 
1515a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1516a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1517a85fe12eSEd Maste }
1518a85fe12eSEd Maste 
1519a85fe12eSEd Maste static void
1520a85fe12eSEd Maste insert_to_strtab(struct section *t, const char *s)
1521a85fe12eSEd Maste {
1522a85fe12eSEd Maste 	const char	*r;
1523a85fe12eSEd Maste 	char		*b, *c;
1524a85fe12eSEd Maste 	size_t		 len, slen;
1525a85fe12eSEd Maste 	int		 append;
1526a85fe12eSEd Maste 
1527a85fe12eSEd Maste 	if (t->sz == 0) {
1528a85fe12eSEd Maste 		t->cap = 512;
1529a85fe12eSEd Maste 		if ((t->buf = malloc(t->cap)) == NULL)
1530a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
1531a85fe12eSEd Maste 	}
1532a85fe12eSEd Maste 
1533a85fe12eSEd Maste 	slen = strlen(s);
1534a85fe12eSEd Maste 	append = 0;
1535a85fe12eSEd Maste 	b = t->buf;
1536a85fe12eSEd Maste 	for (c = b; c < b + t->sz;) {
1537a85fe12eSEd Maste 		len = strlen(c);
1538a85fe12eSEd Maste 		if (!append && len >= slen) {
1539a85fe12eSEd Maste 			r = c + (len - slen);
1540a85fe12eSEd Maste 			if (strcmp(r, s) == 0)
1541a85fe12eSEd Maste 				return;
1542a85fe12eSEd Maste 		} else if (len < slen && len != 0) {
1543a85fe12eSEd Maste 			r = s + (slen - len);
1544a85fe12eSEd Maste 			if (strcmp(c, r) == 0) {
1545a85fe12eSEd Maste 				t->sz -= len + 1;
1546a85fe12eSEd Maste 				memmove(c, c + len + 1, t->sz - (c - b));
1547a85fe12eSEd Maste 				append = 1;
1548a85fe12eSEd Maste 				continue;
1549a85fe12eSEd Maste 			}
1550a85fe12eSEd Maste 		}
1551a85fe12eSEd Maste 		c += len + 1;
1552a85fe12eSEd Maste 	}
1553a85fe12eSEd Maste 
1554a85fe12eSEd Maste 	while (t->sz + slen + 1 >= t->cap) {
1555a85fe12eSEd Maste 		t->cap *= 2;
1556a85fe12eSEd Maste 		if ((t->buf = realloc(t->buf, t->cap)) == NULL)
1557a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");
1558a85fe12eSEd Maste 	}
1559a85fe12eSEd Maste 	b = t->buf;
1560a85fe12eSEd Maste 	strncpy(&b[t->sz], s, slen);
1561a85fe12eSEd Maste 	b[t->sz + slen] = '\0';
1562a85fe12eSEd Maste 	t->sz += slen + 1;
1563a85fe12eSEd Maste }
1564a85fe12eSEd Maste 
1565a85fe12eSEd Maste static int
1566a85fe12eSEd Maste lookup_string(struct section *t, const char *s)
1567a85fe12eSEd Maste {
1568a85fe12eSEd Maste 	const char	*b, *c, *r;
1569a85fe12eSEd Maste 	size_t		 len, slen;
1570a85fe12eSEd Maste 
1571a85fe12eSEd Maste 	slen = strlen(s);
1572a85fe12eSEd Maste 	b = t->buf;
1573a85fe12eSEd Maste 	for (c = b; c < b + t->sz;) {
1574a85fe12eSEd Maste 		len = strlen(c);
1575a85fe12eSEd Maste 		if (len >= slen) {
1576a85fe12eSEd Maste 			r = c + (len - slen);
1577a85fe12eSEd Maste 			if (strcmp(r, s) == 0)
1578a85fe12eSEd Maste 				return (r - b);
1579a85fe12eSEd Maste 		}
1580a85fe12eSEd Maste 		c += len + 1;
1581a85fe12eSEd Maste 	}
1582a85fe12eSEd Maste 
1583a85fe12eSEd Maste 	return (-1);
1584a85fe12eSEd Maste }
1585a85fe12eSEd Maste 
1586a85fe12eSEd Maste static uint32_t crctable[256] =
1587a85fe12eSEd Maste {
1588a85fe12eSEd Maste 	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
1589a85fe12eSEd Maste 	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
1590a85fe12eSEd Maste 	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
1591a85fe12eSEd Maste 	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
1592a85fe12eSEd Maste 	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
1593a85fe12eSEd Maste 	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
1594a85fe12eSEd Maste 	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
1595a85fe12eSEd Maste 	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
1596a85fe12eSEd Maste 	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
1597a85fe12eSEd Maste 	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
1598a85fe12eSEd Maste 	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
1599a85fe12eSEd Maste 	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
1600a85fe12eSEd Maste 	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
1601a85fe12eSEd Maste 	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
1602a85fe12eSEd Maste 	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
1603a85fe12eSEd Maste 	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
1604a85fe12eSEd Maste 	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
1605a85fe12eSEd Maste 	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
1606a85fe12eSEd Maste 	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
1607a85fe12eSEd Maste 	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
1608a85fe12eSEd Maste 	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
1609a85fe12eSEd Maste 	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
1610a85fe12eSEd Maste 	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
1611a85fe12eSEd Maste 	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
1612a85fe12eSEd Maste 	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
1613a85fe12eSEd Maste 	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
1614a85fe12eSEd Maste 	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
1615a85fe12eSEd Maste 	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
1616a85fe12eSEd Maste 	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
1617a85fe12eSEd Maste 	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
1618a85fe12eSEd Maste 	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
1619a85fe12eSEd Maste 	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
1620a85fe12eSEd Maste 	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
1621a85fe12eSEd Maste 	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
1622a85fe12eSEd Maste 	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
1623a85fe12eSEd Maste 	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
1624a85fe12eSEd Maste 	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
1625a85fe12eSEd Maste 	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
1626a85fe12eSEd Maste 	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
1627a85fe12eSEd Maste 	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
1628a85fe12eSEd Maste 	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
1629a85fe12eSEd Maste 	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
1630a85fe12eSEd Maste 	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
1631a85fe12eSEd Maste 	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
1632a85fe12eSEd Maste 	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
1633a85fe12eSEd Maste 	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
1634a85fe12eSEd Maste 	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
1635a85fe12eSEd Maste 	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
1636a85fe12eSEd Maste 	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
1637a85fe12eSEd Maste 	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
1638a85fe12eSEd Maste 	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
1639a85fe12eSEd Maste 	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
1640a85fe12eSEd Maste 	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
1641a85fe12eSEd Maste 	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
1642a85fe12eSEd Maste 	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
1643a85fe12eSEd Maste 	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
1644a85fe12eSEd Maste 	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
1645a85fe12eSEd Maste 	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
1646a85fe12eSEd Maste 	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
1647a85fe12eSEd Maste 	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
1648a85fe12eSEd Maste 	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
1649a85fe12eSEd Maste 	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
1650a85fe12eSEd Maste 	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
1651a85fe12eSEd Maste 	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
1652a85fe12eSEd Maste };
1653a85fe12eSEd Maste 
1654a85fe12eSEd Maste static uint32_t
1655a85fe12eSEd Maste calc_crc32(const char *p, size_t len, uint32_t crc)
1656a85fe12eSEd Maste {
1657a85fe12eSEd Maste 	uint32_t i;
1658a85fe12eSEd Maste 
1659a85fe12eSEd Maste 	for (i = 0; i < len; i++) {
1660a85fe12eSEd Maste 		crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
1661a85fe12eSEd Maste 	}
1662a85fe12eSEd Maste 
1663a85fe12eSEd Maste 	return (crc ^ 0xFFFFFFFF);
1664a85fe12eSEd Maste }
1665