xref: /freebsd/contrib/elftoolchain/elfcopy/sections.c (revision b00fe64f4acfe315181f65999af16e9a7bdc600b)
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*b00fe64fSEd Maste ELFTC_VCSID("$Id: sections.c 3185 2015-04-11 08:56:34Z 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);
59a85fe12eSEd Maste 
60a85fe12eSEd Maste int
61a85fe12eSEd Maste is_remove_section(struct elfcopy *ecp, const char *name)
62a85fe12eSEd Maste {
63a85fe12eSEd Maste 
64a85fe12eSEd Maste 	/* Always keep section name table */
65a85fe12eSEd Maste 	if (strcmp(name, ".shstrtab") == 0)
66a85fe12eSEd Maste 		return 0;
67a85fe12eSEd Maste 	if (strcmp(name, ".symtab") == 0 ||
68a85fe12eSEd Maste 	    strcmp(name, ".strtab") == 0) {
69a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL && lookup_symop_list(
70a85fe12eSEd Maste 		    ecp, NULL, SYMOP_KEEP) == NULL)
71a85fe12eSEd Maste 			return (1);
72a85fe12eSEd Maste 		else
73a85fe12eSEd Maste 			return (0);
74a85fe12eSEd Maste 	}
75a85fe12eSEd Maste 
7667d97fe7SEd Maste 	if (ecp->strip == STRIP_DWO && is_dwo_section(name))
7767d97fe7SEd Maste 		return (1);
7867d97fe7SEd Maste 	if (ecp->strip == STRIP_NONDWO && !is_dwo_section(name))
7967d97fe7SEd Maste 		return (1);
8067d97fe7SEd Maste 
81a85fe12eSEd Maste 	if (is_debug_section(name)) {
82a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL ||
83a85fe12eSEd Maste 		    ecp->strip == STRIP_DEBUG ||
84a85fe12eSEd Maste 		    ecp->strip == STRIP_UNNEEDED ||
85a85fe12eSEd Maste 		    (ecp->flags & DISCARD_LOCAL))
86a85fe12eSEd Maste 			return (1);
87a85fe12eSEd Maste 		if (ecp->strip == STRIP_NONDEBUG)
88a85fe12eSEd Maste 			return (0);
89a85fe12eSEd Maste 	}
90a85fe12eSEd Maste 
91a85fe12eSEd Maste 	if ((ecp->flags & SEC_REMOVE) || (ecp->flags & SEC_COPY)) {
92a85fe12eSEd Maste 		struct sec_action *sac;
93a85fe12eSEd Maste 
94a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, name, 0);
95a85fe12eSEd Maste 		if ((ecp->flags & SEC_REMOVE) && sac != NULL && sac->remove)
96a85fe12eSEd Maste 			return (1);
97a85fe12eSEd Maste 		if ((ecp->flags & SEC_COPY) && (sac == NULL || !sac->copy))
98a85fe12eSEd Maste 			return (1);
99a85fe12eSEd Maste 	}
100a85fe12eSEd Maste 
101a85fe12eSEd Maste 	return (0);
102a85fe12eSEd Maste }
103a85fe12eSEd Maste 
104a85fe12eSEd Maste /*
105a85fe12eSEd Maste  * Relocation section needs to be removed if the section it applies to
106a85fe12eSEd Maste  * will be removed.
107a85fe12eSEd Maste  */
108a85fe12eSEd Maste int
109a85fe12eSEd Maste is_remove_reloc_sec(struct elfcopy *ecp, uint32_t sh_info)
110a85fe12eSEd Maste {
111a85fe12eSEd Maste 	const char	*name;
112a85fe12eSEd Maste 	GElf_Shdr	 ish;
113a85fe12eSEd Maste 	Elf_Scn		*is;
114a85fe12eSEd Maste 	size_t		 indx;
115a85fe12eSEd Maste 	int		 elferr;
116a85fe12eSEd Maste 
117a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
118a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
119a85fe12eSEd Maste 		    elf_errmsg(-1));
120a85fe12eSEd Maste 
121a85fe12eSEd Maste 	is = NULL;
122a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
123a85fe12eSEd Maste 		if (sh_info == elf_ndxscn(is)) {
124a85fe12eSEd Maste 			if (gelf_getshdr(is, &ish) == NULL)
125a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getshdr failed: %s",
126a85fe12eSEd Maste 				    elf_errmsg(-1));
127a85fe12eSEd Maste 			if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) ==
128a85fe12eSEd Maste 			    NULL)
129a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_strptr failed: %s",
130a85fe12eSEd Maste 				    elf_errmsg(-1));
131a85fe12eSEd Maste 			if (is_remove_section(ecp, name))
132a85fe12eSEd Maste 				return (1);
133a85fe12eSEd Maste 			else
134a85fe12eSEd Maste 				return (0);
135a85fe12eSEd Maste 		}
136a85fe12eSEd Maste 	}
137a85fe12eSEd Maste 	elferr = elf_errno();
138a85fe12eSEd Maste 	if (elferr != 0)
139a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
140a85fe12eSEd Maste 		    elf_errmsg(elferr));
141a85fe12eSEd Maste 
142a85fe12eSEd Maste 	/* Remove reloc section if we can't find the target section. */
143a85fe12eSEd Maste 	return (1);
144a85fe12eSEd Maste }
145a85fe12eSEd Maste 
146a85fe12eSEd Maste static int
147a85fe12eSEd Maste is_append_section(struct elfcopy *ecp, const char *name)
148a85fe12eSEd Maste {
149a85fe12eSEd Maste 	struct sec_action *sac;
150a85fe12eSEd Maste 
151a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
152a85fe12eSEd Maste 	if (sac != NULL && sac->append != 0 && sac->string != NULL)
153a85fe12eSEd Maste 		return (1);
154a85fe12eSEd Maste 
155a85fe12eSEd Maste 	return (0);
156a85fe12eSEd Maste }
157a85fe12eSEd Maste 
158a85fe12eSEd Maste static int
159a85fe12eSEd Maste is_compress_section(struct elfcopy *ecp, const char *name)
160a85fe12eSEd Maste {
161a85fe12eSEd Maste 	struct sec_action *sac;
162a85fe12eSEd Maste 
163a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
164a85fe12eSEd Maste 	if (sac != NULL && sac->compress != 0)
165a85fe12eSEd Maste 		return (1);
166a85fe12eSEd Maste 
167a85fe12eSEd Maste 	return (0);
168a85fe12eSEd Maste }
169a85fe12eSEd Maste 
170a85fe12eSEd Maste static void
171a85fe12eSEd Maste check_section_rename(struct elfcopy *ecp, struct section *s)
172a85fe12eSEd Maste {
173a85fe12eSEd Maste 	struct sec_action *sac;
174a85fe12eSEd Maste 	char *prefix;
175a85fe12eSEd Maste 	size_t namelen;
176a85fe12eSEd Maste 
177a85fe12eSEd Maste 	if (s->pseudo)
178a85fe12eSEd Maste 		return;
179a85fe12eSEd Maste 
180a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, s->name, 0);
181a85fe12eSEd Maste 	if (sac != NULL && sac->rename)
182a85fe12eSEd Maste 		s->name = sac->newname;
183a85fe12eSEd Maste 
184a85fe12eSEd Maste 	if (!strcmp(s->name, ".symtab") ||
185a85fe12eSEd Maste 	    !strcmp(s->name, ".strtab") ||
186a85fe12eSEd Maste 	    !strcmp(s->name, ".shstrtab"))
187a85fe12eSEd Maste 		return;
188a85fe12eSEd Maste 
189a85fe12eSEd Maste 	prefix = NULL;
190a85fe12eSEd Maste 	if (s->loadable && ecp->prefix_alloc != NULL)
191a85fe12eSEd Maste 		prefix = ecp->prefix_alloc;
192a85fe12eSEd Maste 	else if (ecp->prefix_sec != NULL)
193a85fe12eSEd Maste 		prefix = ecp->prefix_sec;
194a85fe12eSEd Maste 
195a85fe12eSEd Maste 	if (prefix != NULL) {
196a85fe12eSEd Maste 		namelen = strlen(s->name) + strlen(prefix) + 1;
197a85fe12eSEd Maste 		if ((s->newname = malloc(namelen)) == NULL)
198a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
199a85fe12eSEd Maste 		snprintf(s->newname, namelen, "%s%s", prefix, s->name);
200a85fe12eSEd Maste 		s->name = s->newname;
201a85fe12eSEd Maste 	}
202a85fe12eSEd Maste }
203a85fe12eSEd Maste 
204a85fe12eSEd Maste static int
205a85fe12eSEd Maste get_section_flags(struct elfcopy *ecp, const char *name)
206a85fe12eSEd Maste {
207a85fe12eSEd Maste 	struct sec_action *sac;
208a85fe12eSEd Maste 
209a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
210a85fe12eSEd Maste 	if (sac != NULL && sac->flags)
211a85fe12eSEd Maste 		return sac->flags;
212a85fe12eSEd Maste 
213a85fe12eSEd Maste 	return (0);
214a85fe12eSEd Maste }
215a85fe12eSEd Maste 
216a85fe12eSEd Maste /*
217a85fe12eSEd Maste  * Determine whether the section are debugging section.
218a85fe12eSEd Maste  * According to libbfd, debugging sections are recognized
219a85fe12eSEd Maste  * only by name.
220a85fe12eSEd Maste  */
221a85fe12eSEd Maste static int
222a85fe12eSEd Maste is_debug_section(const char *name)
223a85fe12eSEd Maste {
224a85fe12eSEd Maste 	const char *dbg_sec[] = {
225a85fe12eSEd Maste 		".debug",
226a85fe12eSEd Maste 		".gnu.linkonce.wi.",
227a85fe12eSEd Maste 		".line",
228a85fe12eSEd Maste 		".stab",
229a85fe12eSEd Maste 		NULL
230a85fe12eSEd Maste 	};
231a85fe12eSEd Maste 	const char **p;
232a85fe12eSEd Maste 
233a85fe12eSEd Maste 	for(p = dbg_sec; *p; p++) {
234a85fe12eSEd Maste 		if (strncmp(name, *p, strlen(*p)) == 0)
235a85fe12eSEd Maste 			return (1);
236a85fe12eSEd Maste 	}
237a85fe12eSEd Maste 
238a85fe12eSEd Maste 	return (0);
239a85fe12eSEd Maste }
240a85fe12eSEd Maste 
241a85fe12eSEd Maste static int
24267d97fe7SEd Maste is_dwo_section(const char *name)
24367d97fe7SEd Maste {
24467d97fe7SEd Maste 	size_t len;
24567d97fe7SEd Maste 
24667d97fe7SEd Maste 	if ((len = strlen(name)) > 4 && strcmp(name + len - 4, ".dwo") == 0)
24767d97fe7SEd Maste 		return (1);
24867d97fe7SEd Maste 	return (0);
24967d97fe7SEd Maste }
25067d97fe7SEd Maste 
25167d97fe7SEd Maste static int
252a85fe12eSEd Maste is_print_section(struct elfcopy *ecp, const char *name)
253a85fe12eSEd Maste {
254a85fe12eSEd Maste 	struct sec_action *sac;
255a85fe12eSEd Maste 
256a85fe12eSEd Maste 	sac = lookup_sec_act(ecp, name, 0);
257a85fe12eSEd Maste 	if (sac != NULL && sac->print != 0)
258a85fe12eSEd Maste 		return (1);
259a85fe12eSEd Maste 
260a85fe12eSEd Maste 	return (0);
261a85fe12eSEd Maste }
262a85fe12eSEd Maste 
263a85fe12eSEd Maste static int
264a85fe12eSEd Maste is_modify_section(struct elfcopy *ecp, const char *name)
265a85fe12eSEd Maste {
266a85fe12eSEd Maste 
267a85fe12eSEd Maste 	if (is_append_section(ecp, name) ||
268a85fe12eSEd Maste 	    is_compress_section(ecp, name))
269a85fe12eSEd Maste 		return (1);
270a85fe12eSEd Maste 
271a85fe12eSEd Maste 	return (0);
272a85fe12eSEd Maste }
273a85fe12eSEd Maste 
274a85fe12eSEd Maste struct sec_action*
275a85fe12eSEd Maste lookup_sec_act(struct elfcopy *ecp, const char *name, int add)
276a85fe12eSEd Maste {
277a85fe12eSEd Maste 	struct sec_action *sac;
278a85fe12eSEd Maste 
279a85fe12eSEd Maste 	if (name == NULL)
280a85fe12eSEd Maste 		return NULL;
281a85fe12eSEd Maste 
282a85fe12eSEd Maste 	STAILQ_FOREACH(sac, &ecp->v_sac, sac_list) {
283a85fe12eSEd Maste 		if (strcmp(name, sac->name) == 0)
284a85fe12eSEd Maste 			return sac;
285a85fe12eSEd Maste 	}
286a85fe12eSEd Maste 
287a85fe12eSEd Maste 	if (add == 0)
288a85fe12eSEd Maste 		return NULL;
289a85fe12eSEd Maste 
290a85fe12eSEd Maste 	if ((sac = malloc(sizeof(*sac))) == NULL)
291a85fe12eSEd Maste 		errx(EXIT_FAILURE, "not enough memory");
292a85fe12eSEd Maste 	memset(sac, 0, sizeof(*sac));
293a85fe12eSEd Maste 	sac->name = name;
294a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sac, sac, sac_list);
295a85fe12eSEd Maste 
296a85fe12eSEd Maste 	return (sac);
297a85fe12eSEd Maste }
298a85fe12eSEd Maste 
299a85fe12eSEd Maste void
300a85fe12eSEd Maste free_sec_act(struct elfcopy *ecp)
301a85fe12eSEd Maste {
302a85fe12eSEd Maste 	struct sec_action *sac, *sac_temp;
303a85fe12eSEd Maste 
304a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sac, &ecp->v_sac, sac_list, sac_temp) {
305a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sac, sac, sec_action, sac_list);
306a85fe12eSEd Maste 		free(sac);
307a85fe12eSEd Maste 	}
308a85fe12eSEd Maste }
309a85fe12eSEd Maste 
310a85fe12eSEd Maste void
311a85fe12eSEd Maste insert_to_sec_list(struct elfcopy *ecp, struct section *sec, int tail)
312a85fe12eSEd Maste {
313a85fe12eSEd Maste 	struct section *s;
314a85fe12eSEd Maste 
315a85fe12eSEd Maste 	if (!tail) {
316a85fe12eSEd Maste 		TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
317a85fe12eSEd Maste 			if (sec->off < s->off) {
318a85fe12eSEd Maste 				TAILQ_INSERT_BEFORE(s, sec, sec_list);
319a85fe12eSEd Maste 				goto inc_nos;
320a85fe12eSEd Maste 			}
321a85fe12eSEd Maste 		}
322a85fe12eSEd Maste 	}
323a85fe12eSEd Maste 
324a85fe12eSEd Maste 	TAILQ_INSERT_TAIL(&ecp->v_sec, sec, sec_list);
325a85fe12eSEd Maste 
326a85fe12eSEd Maste inc_nos:
327a85fe12eSEd Maste 	if (sec->pseudo == 0)
328a85fe12eSEd Maste 		ecp->nos++;
329a85fe12eSEd Maste }
330a85fe12eSEd Maste 
331a85fe12eSEd Maste /*
332a85fe12eSEd Maste  * First step of section creation: create scn and internal section
333a85fe12eSEd Maste  * structure, discard sections to be removed.
334a85fe12eSEd Maste  */
335a85fe12eSEd Maste void
336a85fe12eSEd Maste create_scn(struct elfcopy *ecp)
337a85fe12eSEd Maste {
338a85fe12eSEd Maste 	struct section	*s;
339a85fe12eSEd Maste 	const char	*name;
340a85fe12eSEd Maste 	Elf_Scn		*is;
341a85fe12eSEd Maste 	GElf_Shdr	 ish;
342a85fe12eSEd Maste 	size_t		 indx;
343a85fe12eSEd Maste 	uint64_t	 oldndx, newndx;
344a85fe12eSEd Maste 	int		 elferr, sec_flags;
345a85fe12eSEd Maste 
346a85fe12eSEd Maste 	/*
347a85fe12eSEd Maste 	 * Insert a pseudo section that contains the ELF header
348a85fe12eSEd Maste 	 * and program header. Used as reference for section offset
349a85fe12eSEd Maste 	 * or load address adjustment.
350a85fe12eSEd Maste 	 */
351a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
352a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
353a85fe12eSEd Maste 	s->off = 0;
354a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, ELF_T_EHDR, 1, EV_CURRENT) +
355a85fe12eSEd Maste 	    gelf_fsize(ecp->eout, ELF_T_PHDR, ecp->ophnum, EV_CURRENT);
356a85fe12eSEd Maste 	s->align = 1;
357a85fe12eSEd Maste 	s->pseudo = 1;
358a85fe12eSEd Maste 	s->loadable = add_to_inseg_list(ecp, s);
359a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 0);
360a85fe12eSEd Maste 
361a85fe12eSEd Maste 	/* Create internal .shstrtab section. */
362a85fe12eSEd Maste 	init_shstrtab(ecp);
363a85fe12eSEd Maste 
364a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
365a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
366a85fe12eSEd Maste 		    elf_errmsg(-1));
367a85fe12eSEd Maste 
368a85fe12eSEd Maste 	is = NULL;
369a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
370a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) == NULL)
371a85fe12eSEd Maste 			errx(EXIT_FAILURE, "219 gelf_getshdr failed: %s",
372a85fe12eSEd Maste 			    elf_errmsg(-1));
373a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, ish.sh_name)) == NULL)
374a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
375a85fe12eSEd Maste 			    elf_errmsg(-1));
376a85fe12eSEd Maste 
377a85fe12eSEd Maste 		/* Skip sections to be removed. */
378a85fe12eSEd Maste 		if (is_remove_section(ecp, name))
379a85fe12eSEd Maste 			continue;
380a85fe12eSEd Maste 
381a85fe12eSEd Maste 		/*
382a85fe12eSEd Maste 		 * Relocation section need to be remove if the section
383a85fe12eSEd Maste 		 * it applies will be removed.
384a85fe12eSEd Maste 		 */
385a85fe12eSEd Maste 		if (ish.sh_type == SHT_REL || ish.sh_type == SHT_RELA)
386a85fe12eSEd Maste 			if (ish.sh_info != 0 &&
387a85fe12eSEd Maste 			    is_remove_reloc_sec(ecp, ish.sh_info))
388a85fe12eSEd Maste 				continue;
389a85fe12eSEd Maste 
390cf781b2eSEd Maste 		/*
391cf781b2eSEd Maste 		 * Section groups should be removed if symbol table will
392cf781b2eSEd Maste 		 * be removed. (section group's signature stored in symbol
393cf781b2eSEd Maste 		 * table)
394cf781b2eSEd Maste 		 */
395cf781b2eSEd Maste 		if (ish.sh_type == SHT_GROUP && ecp->strip == STRIP_ALL)
396cf781b2eSEd Maste 			continue;
397cf781b2eSEd Maste 
398a85fe12eSEd Maste 		/* Get section flags set by user. */
399a85fe12eSEd Maste 		sec_flags = get_section_flags(ecp, name);
400a85fe12eSEd Maste 
401a85fe12eSEd Maste 		/* Create internal section object. */
402a85fe12eSEd Maste 		if (strcmp(name, ".shstrtab") != 0) {
403a85fe12eSEd Maste 			if ((s = calloc(1, sizeof(*s))) == NULL)
404a85fe12eSEd Maste 				err(EXIT_FAILURE, "calloc failed");
405a85fe12eSEd Maste 			s->name		= name;
406a85fe12eSEd Maste 			s->is		= is;
407a85fe12eSEd Maste 			s->off		= ish.sh_offset;
408a85fe12eSEd Maste 			s->sz		= ish.sh_size;
409a85fe12eSEd Maste 			s->align	= ish.sh_addralign;
410a85fe12eSEd Maste 			s->type		= ish.sh_type;
411a85fe12eSEd Maste 			s->vma		= ish.sh_addr;
412a85fe12eSEd Maste 
413a85fe12eSEd Maste 			/*
414a85fe12eSEd Maste 			 * Search program headers to determine whether section
415a85fe12eSEd Maste 			 * is loadable, but if user explicitly set section flags
416a85fe12eSEd Maste 			 * while neither "load" nor "alloc" is set, we make the
417a85fe12eSEd Maste 			 * section unloadable.
418a85fe12eSEd Maste 			 */
419a85fe12eSEd Maste 			if (sec_flags &&
420a85fe12eSEd Maste 			    (sec_flags & (SF_LOAD | SF_ALLOC)) == 0)
421a85fe12eSEd Maste 				s->loadable = 0;
422a85fe12eSEd Maste 			else
423a85fe12eSEd Maste 				s->loadable = add_to_inseg_list(ecp, s);
424a85fe12eSEd Maste 		} else {
425a85fe12eSEd Maste 			/* Assuming .shstrtab is "unloadable". */
426a85fe12eSEd Maste 			s		= ecp->shstrtab;
427a85fe12eSEd Maste 			s->off		= ish.sh_offset;
428a85fe12eSEd Maste 		}
429a85fe12eSEd Maste 
430a85fe12eSEd Maste 		oldndx = newndx = SHN_UNDEF;
431a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
432a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0) {
433a85fe12eSEd Maste 			if (!strcmp(name, ".shstrtab")) {
434a85fe12eSEd Maste 				/*
435a85fe12eSEd Maste 				 * Add sections specified by --add-section and
436a85fe12eSEd Maste 				 * gnu debuglink. we want these sections have
437a85fe12eSEd Maste 				 * smaller index than .shstrtab section.
438a85fe12eSEd Maste 				 */
439a85fe12eSEd Maste 				if (ecp->debuglink != NULL)
440a85fe12eSEd Maste 					add_gnu_debuglink(ecp);
441a85fe12eSEd Maste 				if (ecp->flags & SEC_ADD)
442a85fe12eSEd Maste 					insert_sections(ecp);
443a85fe12eSEd Maste 			}
444a85fe12eSEd Maste  			if ((s->os = elf_newscn(ecp->eout)) == NULL)
445a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_newscn failed: %s",
446a85fe12eSEd Maste 				    elf_errmsg(-1));
447a85fe12eSEd Maste 			if ((newndx = elf_ndxscn(s->os)) == SHN_UNDEF)
448a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
449a85fe12eSEd Maste 				    elf_errmsg(-1));
450a85fe12eSEd Maste 		}
451a85fe12eSEd Maste 		if ((oldndx = elf_ndxscn(is)) == SHN_UNDEF)
452a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
453a85fe12eSEd Maste 			    elf_errmsg(-1));
454a85fe12eSEd Maste 		if (oldndx != SHN_UNDEF && newndx != SHN_UNDEF)
455a85fe12eSEd Maste 			ecp->secndx[oldndx] = newndx;
456a85fe12eSEd Maste 
457a85fe12eSEd Maste 		/*
458a85fe12eSEd Maste 		 * If strip action is STRIP_NONDEBUG(only keep debug),
459a85fe12eSEd Maste 		 * change sections flags of loadable sections to SHF_NOBITS,
460a85fe12eSEd Maste 		 * and the content of those sections will be ignored.
461a85fe12eSEd Maste 		 */
462a85fe12eSEd Maste 		if (ecp->strip == STRIP_NONDEBUG && (ish.sh_flags & SHF_ALLOC))
463a85fe12eSEd Maste 			s->type = SHT_NOBITS;
464a85fe12eSEd Maste 
465a85fe12eSEd Maste 		check_section_rename(ecp, s);
466a85fe12eSEd Maste 
467a85fe12eSEd Maste 		/* create section header based on input object. */
468a85fe12eSEd Maste 		if (strcmp(name, ".symtab") != 0 &&
469a85fe12eSEd Maste 		    strcmp(name, ".strtab") != 0 &&
470a85fe12eSEd Maste 		    strcmp(name, ".shstrtab") != 0)
471a85fe12eSEd Maste 			copy_shdr(ecp, s, NULL, 0, sec_flags);
472a85fe12eSEd Maste 
473a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0) {
474a85fe12eSEd Maste 			ecp->flags |= SYMTAB_EXIST;
475a85fe12eSEd Maste 			ecp->symtab = s;
476a85fe12eSEd Maste 		}
477a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0)
478a85fe12eSEd Maste 			ecp->strtab = s;
479a85fe12eSEd Maste 
480a85fe12eSEd Maste 		insert_to_sec_list(ecp, s, 0);
481a85fe12eSEd Maste 	}
482a85fe12eSEd Maste 	elferr = elf_errno();
483a85fe12eSEd Maste 	if (elferr != 0)
484a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
485a85fe12eSEd Maste 		    elf_errmsg(elferr));
486a85fe12eSEd Maste }
487a85fe12eSEd Maste 
488a85fe12eSEd Maste struct section *
489a85fe12eSEd Maste insert_shtab(struct elfcopy *ecp, int tail)
490a85fe12eSEd Maste {
491a85fe12eSEd Maste 	struct section	*s, *shtab;
492a85fe12eSEd Maste 	GElf_Ehdr	 ieh;
493a85fe12eSEd Maste 	int		 nsecs;
494a85fe12eSEd Maste 
495a85fe12eSEd Maste 	/*
496a85fe12eSEd Maste 	 * Treat section header table as a "pseudo" section, insert it
497a85fe12eSEd Maste 	 * into section list, so later it will get sorted and resynced
498a85fe12eSEd Maste 	 * just as normal sections.
499a85fe12eSEd Maste 	 */
500a85fe12eSEd Maste 	if ((shtab = calloc(1, sizeof(*shtab))) == NULL)
501a85fe12eSEd Maste 		errx(EXIT_FAILURE, "calloc failed");
502a85fe12eSEd Maste 	if (!tail) {
5034a85c691SEd Maste 		/*
5044a85c691SEd Maste 		 * "shoff" of input object is used as a hint for section
5054a85c691SEd Maste 		 * resync later.
5064a85c691SEd Maste 		 */
507a85fe12eSEd Maste 		if (gelf_getehdr(ecp->ein, &ieh) == NULL)
508a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
509a85fe12eSEd Maste 			    elf_errmsg(-1));
510a85fe12eSEd Maste 		shtab->off = ieh.e_shoff;
511a85fe12eSEd Maste 	} else
512a85fe12eSEd Maste 		shtab->off = 0;
513a85fe12eSEd Maste 	/* Calculate number of sections in the output object. */
514a85fe12eSEd Maste 	nsecs = 0;
515a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
516a85fe12eSEd Maste 		if (!s->pseudo)
517a85fe12eSEd Maste 			nsecs++;
518a85fe12eSEd Maste 	}
519a85fe12eSEd Maste 	/* Remember there is always a null section, so we +1 here. */
520a85fe12eSEd Maste 	shtab->sz = gelf_fsize(ecp->eout, ELF_T_SHDR, nsecs + 1, EV_CURRENT);
521a85fe12eSEd Maste 	if (shtab->sz == 0)
522a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_fsize() failed: %s", elf_errmsg(-1));
523a85fe12eSEd Maste 	shtab->align = (ecp->oec == ELFCLASS32 ? 4 : 8);
524a85fe12eSEd Maste 	shtab->loadable = 0;
525a85fe12eSEd Maste 	shtab->pseudo = 1;
526a85fe12eSEd Maste 	insert_to_sec_list(ecp, shtab, tail);
527a85fe12eSEd Maste 
528a85fe12eSEd Maste 	return (shtab);
529a85fe12eSEd Maste }
530a85fe12eSEd Maste 
531a85fe12eSEd Maste void
532a85fe12eSEd Maste copy_content(struct elfcopy *ecp)
533a85fe12eSEd Maste {
534a85fe12eSEd Maste 	struct section *s;
535a85fe12eSEd Maste 
536a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
537a85fe12eSEd Maste 		/* Skip pseudo section. */
538a85fe12eSEd Maste 		if (s->pseudo)
539a85fe12eSEd Maste 			continue;
540a85fe12eSEd Maste 
541a85fe12eSEd Maste 		/* Skip special sections. */
542a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
543a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
544a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
545a85fe12eSEd Maste 			continue;
546a85fe12eSEd Maste 
547a85fe12eSEd Maste 		/*
548a85fe12eSEd Maste 		 * If strip action is STRIP_ALL, relocation info need
549a85fe12eSEd Maste 		 * to be stripped. Skip filtering otherwisw.
550a85fe12eSEd Maste 		 */
551a85fe12eSEd Maste 		if (ecp->strip == STRIP_ALL &&
552a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
553a85fe12eSEd Maste 			filter_reloc(ecp, s);
554a85fe12eSEd Maste 
555a85fe12eSEd Maste 		if (is_modify_section(ecp, s->name))
556a85fe12eSEd Maste 			modify_section(ecp, s);
557a85fe12eSEd Maste 
558a85fe12eSEd Maste 		copy_data(s);
559a85fe12eSEd Maste 
560a85fe12eSEd Maste 		/*
561a85fe12eSEd Maste 		 * If symbol table is modified, relocation info might
562a85fe12eSEd Maste 		 * need update, as symbol index may have changed.
563a85fe12eSEd Maste 		 */
564a85fe12eSEd Maste 		if ((ecp->flags & SYMTAB_INTACT) == 0 &&
565a85fe12eSEd Maste 		    (ecp->flags & SYMTAB_EXIST) &&
566a85fe12eSEd Maste 		    (s->type == SHT_REL || s->type == SHT_RELA))
567a85fe12eSEd Maste 			update_reloc(ecp, s);
568a85fe12eSEd Maste 
569a85fe12eSEd Maste 		if (is_print_section(ecp, s->name))
570a85fe12eSEd Maste 			print_section(s);
571a85fe12eSEd Maste 	}
572a85fe12eSEd Maste }
573a85fe12eSEd Maste 
574a85fe12eSEd Maste /*
575a85fe12eSEd Maste  * Filter relocation entries, only keep those entries whose
576a85fe12eSEd Maste  * symbol is in the keep list.
577a85fe12eSEd Maste  */
578a85fe12eSEd Maste static void
579a85fe12eSEd Maste filter_reloc(struct elfcopy *ecp, struct section *s)
580a85fe12eSEd Maste {
581a85fe12eSEd Maste 	const char	*name;
582a85fe12eSEd Maste 	GElf_Shdr	 ish;
583a85fe12eSEd Maste 	GElf_Rel	 rel;
584a85fe12eSEd Maste 	GElf_Rela	 rela;
585a85fe12eSEd Maste 	Elf32_Rel	*rel32;
586a85fe12eSEd Maste 	Elf64_Rel	*rel64;
587a85fe12eSEd Maste 	Elf32_Rela	*rela32;
588a85fe12eSEd Maste 	Elf64_Rela	*rela64;
589a85fe12eSEd Maste 	Elf_Data	*id;
590a85fe12eSEd Maste 	uint64_t	 cap, n, nrels;
591a85fe12eSEd Maste 	int		 elferr, i;
592a85fe12eSEd Maste 
593a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
594a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
595a85fe12eSEd Maste 		    elf_errmsg(-1));
596a85fe12eSEd Maste 
597a85fe12eSEd Maste 	/* We don't want to touch relocation info for dynamic symbols. */
598a85fe12eSEd Maste 	if ((ecp->flags & SYMTAB_EXIST) == 0) {
599a85fe12eSEd Maste 		if (ish.sh_link == 0 || ecp->secndx[ish.sh_link] == 0) {
600a85fe12eSEd Maste 			/*
601a85fe12eSEd Maste 			 * This reloc section applies to the symbol table
602a85fe12eSEd Maste 			 * that was stripped, so discard whole section.
603a85fe12eSEd Maste 			 */
604a85fe12eSEd Maste 			s->nocopy = 1;
605a85fe12eSEd Maste 			s->sz = 0;
606a85fe12eSEd Maste 		}
607a85fe12eSEd Maste 		return;
608a85fe12eSEd Maste 	} else {
609a85fe12eSEd Maste 		/* Symbol table exist, check if index equals. */
610a85fe12eSEd Maste 		if (ish.sh_link != elf_ndxscn(ecp->symtab->is))
611a85fe12eSEd Maste 			return;
612a85fe12eSEd Maste 	}
613a85fe12eSEd Maste 
614a85fe12eSEd Maste #define	COPYREL(REL, SZ) do {					\
615a85fe12eSEd Maste 	if (nrels == 0) {					\
616a85fe12eSEd Maste 		if ((REL##SZ = malloc(cap *			\
617a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Rel))) == NULL)		\
618a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");	\
619a85fe12eSEd Maste 	}							\
620a85fe12eSEd Maste 	if (nrels >= cap) {					\
621a85fe12eSEd Maste 		cap *= 2;					\
622a85fe12eSEd Maste 		if ((REL##SZ = realloc(REL##SZ, cap *		\
623a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Rel))) == NULL)		\
624a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");	\
625a85fe12eSEd Maste 	}							\
626a85fe12eSEd Maste 	REL##SZ[nrels].r_offset = REL.r_offset;			\
627a85fe12eSEd Maste 	REL##SZ[nrels].r_info	= REL.r_info;			\
628a85fe12eSEd Maste 	if (s->type == SHT_RELA)				\
629a85fe12eSEd Maste 		rela##SZ[nrels].r_addend = rela.r_addend;	\
630a85fe12eSEd Maste 	nrels++;						\
631a85fe12eSEd Maste } while (0)
632a85fe12eSEd Maste 
633a85fe12eSEd Maste 	nrels = 0;
634a85fe12eSEd Maste 	cap = 4;		/* keep list is usually small. */
635a85fe12eSEd Maste 	rel32 = NULL;
636a85fe12eSEd Maste 	rel64 = NULL;
637a85fe12eSEd Maste 	rela32 = NULL;
638a85fe12eSEd Maste 	rela64 = NULL;
639a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL)
640a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
641a85fe12eSEd Maste 		    elf_errmsg(-1));
642a85fe12eSEd Maste 	n = ish.sh_size / ish.sh_entsize;
643a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
644a85fe12eSEd Maste 		if (s->type == SHT_REL) {
645a85fe12eSEd Maste 			if (gelf_getrel(id, i, &rel) != &rel)
646a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
647a85fe12eSEd Maste 				    elf_errmsg(-1));
648a85fe12eSEd Maste 		} else {
649a85fe12eSEd Maste 			if (gelf_getrela(id, i, &rela) != &rela)
650a85fe12eSEd Maste 				errx(EXIT_FAILURE, "gelf_getrel failed: %s",
651a85fe12eSEd Maste 				    elf_errmsg(-1));
652a85fe12eSEd Maste 		}
653a85fe12eSEd Maste 		name = elf_strptr(ecp->ein, elf_ndxscn(ecp->strtab->is),
654a85fe12eSEd Maste 		    GELF_R_SYM(rel.r_info));
655a85fe12eSEd Maste 		if (name == NULL)
656a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
657a85fe12eSEd Maste 			    elf_errmsg(-1));
658a85fe12eSEd Maste 		if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL) {
659a85fe12eSEd Maste 			if (ecp->oec == ELFCLASS32) {
660a85fe12eSEd Maste 				if (s->type == SHT_REL)
661a85fe12eSEd Maste 					COPYREL(rel, 32);
662a85fe12eSEd Maste 				else
663a85fe12eSEd Maste 					COPYREL(rela, 32);
664a85fe12eSEd Maste 			} else {
665a85fe12eSEd Maste 				if (s->type == SHT_REL)
666a85fe12eSEd Maste 					COPYREL(rel, 64);
667a85fe12eSEd Maste 				else
668a85fe12eSEd Maste 					COPYREL(rela, 64);
669a85fe12eSEd Maste 			}
670a85fe12eSEd Maste 		}
671a85fe12eSEd Maste 	}
672a85fe12eSEd Maste 	elferr = elf_errno();
673a85fe12eSEd Maste 	if (elferr != 0)
674a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
675a85fe12eSEd Maste 		    elf_errmsg(elferr));
676a85fe12eSEd Maste 
677a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32) {
678a85fe12eSEd Maste 		if (s->type == SHT_REL)
679a85fe12eSEd Maste 			s->buf = rel32;
680a85fe12eSEd Maste 		else
681a85fe12eSEd Maste 			s->buf = rela32;
682a85fe12eSEd Maste 	} else {
683a85fe12eSEd Maste 		if (s->type == SHT_REL)
684a85fe12eSEd Maste 			s->buf = rel64;
685a85fe12eSEd Maste 		else
686a85fe12eSEd Maste 			s->buf = rela64;
687a85fe12eSEd Maste 	}
688a85fe12eSEd Maste 	s->sz = gelf_fsize(ecp->eout, (s->type == SHT_REL ? ELF_T_REL :
689a85fe12eSEd Maste 	    ELF_T_RELA), nrels, EV_CURRENT);
690a85fe12eSEd Maste 	s->nocopy = 1;
691a85fe12eSEd Maste }
692a85fe12eSEd Maste 
693a85fe12eSEd Maste static void
694a85fe12eSEd Maste update_reloc(struct elfcopy *ecp, struct section *s)
695a85fe12eSEd Maste {
696a85fe12eSEd Maste 	GElf_Shdr	 osh;
697a85fe12eSEd Maste 	GElf_Rel	 rel;
698a85fe12eSEd Maste 	GElf_Rela	 rela;
699a85fe12eSEd Maste 	Elf_Data	*od;
700a85fe12eSEd Maste 	uint64_t	 n;
701a85fe12eSEd Maste 	int		 i;
702a85fe12eSEd Maste 
703a85fe12eSEd Maste #define UPDATEREL(REL) do {						\
704a85fe12eSEd Maste 	if (gelf_get##REL(od, i, &REL) != &REL)				\
705a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_get##REL failed: %s",		\
706a85fe12eSEd Maste 		    elf_errmsg(-1));					\
707a85fe12eSEd Maste 	REL.r_info = GELF_R_INFO(ecp->symndx[GELF_R_SYM(REL.r_info)],	\
708a85fe12eSEd Maste 	    GELF_R_TYPE(REL.r_info));					\
709a85fe12eSEd Maste 	if (!gelf_update_##REL(od, i, &REL))				\
710a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_##REL failed: %s",	\
711a85fe12eSEd Maste 		    elf_errmsg(-1));					\
712a85fe12eSEd Maste } while(0)
713a85fe12eSEd Maste 
714a85fe12eSEd Maste 	if (s->sz == 0)
715a85fe12eSEd Maste 		return;
716a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
717a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getehdr() failed: %s",
718a85fe12eSEd Maste 		    elf_errmsg(-1));
719a85fe12eSEd Maste 	/* Only process .symtab reloc info. */
720a85fe12eSEd Maste 	if (osh.sh_link != elf_ndxscn(ecp->symtab->is))
721a85fe12eSEd Maste 		return;
722a85fe12eSEd Maste 	if ((od = elf_getdata(s->os, NULL)) == NULL)
723a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
724a85fe12eSEd Maste 		    elf_errmsg(-1));
725a85fe12eSEd Maste 	n = osh.sh_size / osh.sh_entsize;
726a85fe12eSEd Maste 	for(i = 0; (uint64_t)i < n; i++) {
727a85fe12eSEd Maste 		if (s->type == SHT_REL)
728a85fe12eSEd Maste 			UPDATEREL(rel);
729a85fe12eSEd Maste 		else
730a85fe12eSEd Maste 			UPDATEREL(rela);
731a85fe12eSEd Maste 	}
732a85fe12eSEd Maste }
733a85fe12eSEd Maste 
734a85fe12eSEd Maste static void
735a85fe12eSEd Maste pad_section(struct elfcopy *ecp, struct section *s)
736a85fe12eSEd Maste {
737a85fe12eSEd Maste 	GElf_Shdr	 osh;
738a85fe12eSEd Maste 	Elf_Data	*od;
739a85fe12eSEd Maste 
740a85fe12eSEd Maste 	if (s == NULL || s->pad_sz == 0)
741a85fe12eSEd Maste 		return;
742a85fe12eSEd Maste 
743a85fe12eSEd Maste 	if ((s->pad = malloc(s->pad_sz)) == NULL)
744a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
745a85fe12eSEd Maste 	memset(s->pad, ecp->fill, s->pad_sz);
746a85fe12eSEd Maste 
747a85fe12eSEd Maste 	/* Create a new Elf_Data to contain the padding bytes. */
748a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
749a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
750a85fe12eSEd Maste 		    elf_errmsg(-1));
751a85fe12eSEd Maste 	od->d_align = 1;
752a85fe12eSEd Maste 	od->d_off = s->sz;
753a85fe12eSEd Maste 	od->d_buf = s->pad;
754a85fe12eSEd Maste 	od->d_type = ELF_T_BYTE;
755a85fe12eSEd Maste 	od->d_size = s->pad_sz;
756a85fe12eSEd Maste 	od->d_version = EV_CURRENT;
757a85fe12eSEd Maste 
758a85fe12eSEd Maste 	/* Update section header. */
759a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
760a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
761a85fe12eSEd Maste 		    elf_errmsg(-1));
762a85fe12eSEd Maste 	osh.sh_size = s->sz + s->pad_sz;
763a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
764a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
765a85fe12eSEd Maste 		    elf_errmsg(-1));
766a85fe12eSEd Maste }
767a85fe12eSEd Maste 
768a85fe12eSEd Maste void
769a85fe12eSEd Maste resync_sections(struct elfcopy *ecp)
770a85fe12eSEd Maste {
771a85fe12eSEd Maste 	struct section	*s, *ps;
772a85fe12eSEd Maste 	GElf_Shdr	 osh;
773a85fe12eSEd Maste 	uint64_t	 off;
774a85fe12eSEd Maste 	int		 first;
775a85fe12eSEd Maste 
776a85fe12eSEd Maste 	ps = NULL;
777a85fe12eSEd Maste 	first = 1;
778a85fe12eSEd Maste 	off = 0;
779a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
780a85fe12eSEd Maste 		if (first) {
781a85fe12eSEd Maste 			off = s->off;
782a85fe12eSEd Maste 			first = 0;
783a85fe12eSEd Maste 		}
784a85fe12eSEd Maste 
7854a85c691SEd Maste 		/*
7864a85c691SEd Maste 		 * Ignore TLS sections with load address 0 and without
7874a85c691SEd Maste 		 * content. We don't need to adjust their file offset or
7884a85c691SEd Maste 		 * VMA, only the size matters.
7894a85c691SEd Maste 		 */
7904a85c691SEd Maste 		if (s->seg_tls != NULL && s->type == SHT_NOBITS &&
7914a85c691SEd Maste 		    s->off == 0)
7924a85c691SEd Maste 			continue;
7934a85c691SEd Maste 
794a85fe12eSEd Maste 		/* Align section offset. */
7952b39d4f6SEd Maste 		if (s->align == 0)
7962b39d4f6SEd Maste 			s->align = 1;
797a85fe12eSEd Maste 		if (off <= s->off) {
798a85fe12eSEd Maste 			if (!s->loadable)
799a85fe12eSEd Maste 				s->off = roundup(off, s->align);
800a85fe12eSEd Maste 		} else {
801a85fe12eSEd Maste 			if (s->loadable)
80217eee522SEd Maste 				warnx("moving loadable section %s, "
80317eee522SEd Maste 				    "is this intentional?", s->name);
804a85fe12eSEd Maste 			s->off = roundup(off, s->align);
805a85fe12eSEd Maste 		}
806a85fe12eSEd Maste 
807a85fe12eSEd Maste 		/* Calculate next section offset. */
808a85fe12eSEd Maste 		off = s->off;
809a85fe12eSEd Maste 		if (s->pseudo || (s->type != SHT_NOBITS && s->type != SHT_NULL))
810a85fe12eSEd Maste 			off += s->sz;
811a85fe12eSEd Maste 
812a85fe12eSEd Maste 		if (s->pseudo) {
813a85fe12eSEd Maste 			ps = NULL;
814a85fe12eSEd Maste 			continue;
815a85fe12eSEd Maste 		}
816a85fe12eSEd Maste 
817a85fe12eSEd Maste 		/* Count padding bytes added through --pad-to. */
818a85fe12eSEd Maste 		if (s->pad_sz > 0)
819a85fe12eSEd Maste 			off += s->pad_sz;
820a85fe12eSEd Maste 
821a85fe12eSEd Maste 		/* Update section header accordingly. */
822a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
823a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
824a85fe12eSEd Maste 			    elf_errmsg(-1));
825a85fe12eSEd Maste 		osh.sh_addr = s->vma;
826a85fe12eSEd Maste 		osh.sh_offset = s->off;
827a85fe12eSEd Maste 		osh.sh_size = s->sz;
828a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
829a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
830a85fe12eSEd Maste 			    elf_errmsg(-1));
831a85fe12eSEd Maste 
832a85fe12eSEd Maste 		/* Add padding for previous section, if need. */
833a85fe12eSEd Maste 		if (ps != NULL) {
834a85fe12eSEd Maste 			if (ps->pad_sz > 0) {
835a85fe12eSEd Maste 				/* Apply padding added by --pad-to. */
836a85fe12eSEd Maste 				pad_section(ecp, ps);
837a85fe12eSEd Maste 			} else if ((ecp->flags & GAP_FILL) &&
838a85fe12eSEd Maste 			    (ps->off + ps->sz < s->off)) {
839a85fe12eSEd Maste 				/*
840a85fe12eSEd Maste 				 * Fill the gap between sections by padding
841a85fe12eSEd Maste 				 * the section with lower address.
842a85fe12eSEd Maste 				 */
843a85fe12eSEd Maste 				ps->pad_sz = s->off - (ps->off + ps->sz);
844a85fe12eSEd Maste 				pad_section(ecp, ps);
845a85fe12eSEd Maste 			}
846a85fe12eSEd Maste 		}
847a85fe12eSEd Maste 
848a85fe12eSEd Maste 		ps = s;
849a85fe12eSEd Maste 	}
850a85fe12eSEd Maste 
851a85fe12eSEd Maste 	/* Pad the last section, if need. */
852a85fe12eSEd Maste 	if (ps != NULL && ps->pad_sz > 0)
853a85fe12eSEd Maste 		pad_section(ecp, ps);
854a85fe12eSEd Maste }
855a85fe12eSEd Maste 
856a85fe12eSEd Maste static void
857a85fe12eSEd Maste modify_section(struct elfcopy *ecp, struct section *s)
858a85fe12eSEd Maste {
859a85fe12eSEd Maste 	struct sec_action	*sac;
860a85fe12eSEd Maste 	size_t			 srcsz, dstsz, p, len;
861a85fe12eSEd Maste 	char			*b, *c, *d, *src, *end;
862a85fe12eSEd Maste 	int			 dupe;
863a85fe12eSEd Maste 
864a85fe12eSEd Maste 	src = read_section(s, &srcsz);
865a85fe12eSEd Maste 	if (src == NULL || srcsz == 0) {
866a85fe12eSEd Maste 		/* For empty section, we proceed if we need to append. */
867a85fe12eSEd Maste 		if (!is_append_section(ecp, s->name))
868a85fe12eSEd Maste 			return;
869a85fe12eSEd Maste 	}
870a85fe12eSEd Maste 
871a85fe12eSEd Maste 	/* Allocate buffer needed for new section data. */
872a85fe12eSEd Maste 	dstsz = srcsz;
873a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
874a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
875a85fe12eSEd Maste 		dstsz += strlen(sac->string) + 1;
876a85fe12eSEd Maste 	}
877a85fe12eSEd Maste 	if ((b = malloc(dstsz)) == NULL)
878a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
879a85fe12eSEd Maste 	s->buf = b;
880a85fe12eSEd Maste 
881a85fe12eSEd Maste 	/* Compress section. */
882a85fe12eSEd Maste 	p = 0;
883a85fe12eSEd Maste 	if (is_compress_section(ecp, s->name)) {
884a85fe12eSEd Maste 		end = src + srcsz;
885a85fe12eSEd Maste 		for(c = src; c < end;) {
886a85fe12eSEd Maste 			len = 0;
887a85fe12eSEd Maste 			while(c + len < end && c[len] != '\0')
888a85fe12eSEd Maste 				len++;
889a85fe12eSEd Maste 			if (c + len == end) {
890a85fe12eSEd Maste 				/* XXX should we warn here? */
891a85fe12eSEd Maste 				strncpy(&b[p], c, len);
892a85fe12eSEd Maste 				p += len;
893a85fe12eSEd Maste 				break;
894a85fe12eSEd Maste 			}
895a85fe12eSEd Maste 			dupe = 0;
896a85fe12eSEd Maste 			for (d = b; d < b + p; ) {
897a85fe12eSEd Maste 				if (strcmp(d, c) == 0) {
898a85fe12eSEd Maste 					dupe = 1;
899a85fe12eSEd Maste 					break;
900a85fe12eSEd Maste 				}
901a85fe12eSEd Maste 				d += strlen(d) + 1;
902a85fe12eSEd Maste 			}
903a85fe12eSEd Maste 			if (!dupe) {
904a85fe12eSEd Maste 				strncpy(&b[p], c, len);
905a85fe12eSEd Maste 				b[p + len] = '\0';
906a85fe12eSEd Maste 				p += len + 1;
907a85fe12eSEd Maste 			}
908a85fe12eSEd Maste 			c += len + 1;
909a85fe12eSEd Maste 		}
910a85fe12eSEd Maste 	} else {
911a85fe12eSEd Maste 		memcpy(b, src, srcsz);
912a85fe12eSEd Maste 		p += srcsz;
913a85fe12eSEd Maste 	}
914a85fe12eSEd Maste 
915a85fe12eSEd Maste 	/* Append section. */
916a85fe12eSEd Maste 	if (is_append_section(ecp, s->name)) {
917a85fe12eSEd Maste 		sac = lookup_sec_act(ecp, s->name, 0);
918a85fe12eSEd Maste 		len = strlen(sac->string);
919a85fe12eSEd Maste 		strncpy(&b[p], sac->string, len);
920a85fe12eSEd Maste 		b[p + len] = '\0';
921a85fe12eSEd Maste 		p += len + 1;
922a85fe12eSEd Maste 	}
923a85fe12eSEd Maste 
924a85fe12eSEd Maste 	s->sz = p;
925a85fe12eSEd Maste 	s->nocopy = 1;
926a85fe12eSEd Maste }
927a85fe12eSEd Maste 
928a85fe12eSEd Maste static void
929a85fe12eSEd Maste print_data(const char *d, size_t sz)
930a85fe12eSEd Maste {
931a85fe12eSEd Maste 	const char *c;
932a85fe12eSEd Maste 
933a85fe12eSEd Maste 	for (c = d; c < d + sz; c++) {
934a85fe12eSEd Maste 		if (*c == '\0')
935a85fe12eSEd Maste 			putchar('\n');
936a85fe12eSEd Maste 		else
937a85fe12eSEd Maste 			putchar(*c);
938a85fe12eSEd Maste 	}
939a85fe12eSEd Maste }
940a85fe12eSEd Maste 
941a85fe12eSEd Maste static void
942a85fe12eSEd Maste print_section(struct section *s)
943a85fe12eSEd Maste {
944a85fe12eSEd Maste 	Elf_Data	*id;
945a85fe12eSEd Maste 	int		 elferr;
946a85fe12eSEd Maste 
947a85fe12eSEd Maste 	if (s->buf != NULL && s->sz > 0) {
948a85fe12eSEd Maste 		print_data(s->buf, s->sz);
949a85fe12eSEd Maste 	} else {
950a85fe12eSEd Maste 		id = NULL;
951a85fe12eSEd Maste 		while ((id = elf_getdata(s->is, id)) != NULL)
952a85fe12eSEd Maste 			print_data(id->d_buf, id->d_size);
953a85fe12eSEd Maste 		elferr = elf_errno();
954a85fe12eSEd Maste 		if (elferr != 0)
955a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
956a85fe12eSEd Maste 			    elf_errmsg(elferr));
957a85fe12eSEd Maste 	}
958a85fe12eSEd Maste 	putchar('\n');
959a85fe12eSEd Maste }
960a85fe12eSEd Maste 
961a85fe12eSEd Maste static void *
962a85fe12eSEd Maste read_section(struct section *s, size_t *size)
963a85fe12eSEd Maste {
964a85fe12eSEd Maste 	Elf_Data	*id;
965a85fe12eSEd Maste 	char		*b;
966a85fe12eSEd Maste 	size_t		 sz;
967a85fe12eSEd Maste 	int		 elferr;
968a85fe12eSEd Maste 
969a85fe12eSEd Maste 	sz = 0;
970a85fe12eSEd Maste 	b = NULL;
971a85fe12eSEd Maste 	id = NULL;
972a85fe12eSEd Maste 	while ((id = elf_getdata(s->is, id)) != NULL) {
973a85fe12eSEd Maste 		if (b == NULL)
974a85fe12eSEd Maste 			b = malloc(id->d_size);
975a85fe12eSEd Maste 		else
976a85fe12eSEd Maste 			b = malloc(sz + id->d_size);
977a85fe12eSEd Maste 		if (b == NULL)
978a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc or realloc failed");
979a85fe12eSEd Maste 
980a85fe12eSEd Maste 		memcpy(&b[sz], id->d_buf, id->d_size);
981a85fe12eSEd Maste 		sz += id->d_size;
982a85fe12eSEd Maste 	}
983a85fe12eSEd Maste 	elferr = elf_errno();
984a85fe12eSEd Maste 	if (elferr != 0)
985a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getdata() failed: %s",
986a85fe12eSEd Maste 		    elf_errmsg(elferr));
987a85fe12eSEd Maste 
988a85fe12eSEd Maste 	*size = sz;
989a85fe12eSEd Maste 
990a85fe12eSEd Maste 	return (b);
991a85fe12eSEd Maste }
992a85fe12eSEd Maste 
993a85fe12eSEd Maste void
994a85fe12eSEd Maste copy_shdr(struct elfcopy *ecp, struct section *s, const char *name, int copy,
995a85fe12eSEd Maste     int sec_flags)
996a85fe12eSEd Maste {
997a85fe12eSEd Maste 	GElf_Shdr ish, osh;
998a85fe12eSEd Maste 
999a85fe12eSEd Maste 	if (gelf_getshdr(s->is, &ish) == NULL)
1000a85fe12eSEd Maste 		errx(EXIT_FAILURE, "526 gelf_getshdr() failed: %s",
1001a85fe12eSEd Maste 		    elf_errmsg(-1));
1002a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &osh) == NULL)
1003a85fe12eSEd Maste 		errx(EXIT_FAILURE, "529 gelf_getshdr() failed: %s",
1004a85fe12eSEd Maste 		    elf_errmsg(-1));
1005a85fe12eSEd Maste 
1006a85fe12eSEd Maste 	if (copy)
1007a85fe12eSEd Maste 		(void) memcpy(&osh, &ish, sizeof(ish));
1008a85fe12eSEd Maste 	else {
1009a85fe12eSEd Maste 		osh.sh_type		= s->type;
1010a85fe12eSEd Maste 		osh.sh_addr		= s->vma;
1011a85fe12eSEd Maste 		osh.sh_offset		= s->off;
1012a85fe12eSEd Maste 		osh.sh_size		= s->sz;
1013a85fe12eSEd Maste 		osh.sh_link		= ish.sh_link;
1014a85fe12eSEd Maste 		osh.sh_info		= ish.sh_info;
1015a85fe12eSEd Maste 		osh.sh_addralign	= s->align;
1016a85fe12eSEd Maste 		osh.sh_entsize		= ish.sh_entsize;
1017a85fe12eSEd Maste 
1018a85fe12eSEd Maste 		if (sec_flags) {
1019a85fe12eSEd Maste 			osh.sh_flags = 0;
1020a85fe12eSEd Maste 			if (sec_flags & SF_ALLOC) {
1021a85fe12eSEd Maste 				osh.sh_flags |= SHF_ALLOC;
1022a85fe12eSEd Maste 				if (!s->loadable)
1023a85fe12eSEd Maste 					warnx("set SHF_ALLOC flag for "
1024a85fe12eSEd Maste 					    "unloadable section %s",
1025a85fe12eSEd Maste 					    s->name);
1026a85fe12eSEd Maste 			}
1027a85fe12eSEd Maste 			if ((sec_flags & SF_READONLY) == 0)
1028a85fe12eSEd Maste 				osh.sh_flags |= SHF_WRITE;
1029a85fe12eSEd Maste 			if (sec_flags & SF_CODE)
1030a85fe12eSEd Maste 				osh.sh_flags |= SHF_EXECINSTR;
1031a85fe12eSEd Maste 		} else
1032a85fe12eSEd Maste 			osh.sh_flags = ish.sh_flags;
1033a85fe12eSEd Maste 	}
1034a85fe12eSEd Maste 
1035a85fe12eSEd Maste 	if (name == NULL)
1036a85fe12eSEd Maste 		add_to_shstrtab(ecp, s->name);
1037a85fe12eSEd Maste 	else
1038a85fe12eSEd Maste 		add_to_shstrtab(ecp, name);
1039a85fe12eSEd Maste 
1040a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &osh))
1041a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_update_shdr failed: %s",
1042a85fe12eSEd Maste 		    elf_errmsg(-1));
1043a85fe12eSEd Maste }
1044a85fe12eSEd Maste 
1045a85fe12eSEd Maste void
1046a85fe12eSEd Maste copy_data(struct section *s)
1047a85fe12eSEd Maste {
1048a85fe12eSEd Maste 	Elf_Data	*id, *od;
1049a85fe12eSEd Maste 	int		 elferr;
1050a85fe12eSEd Maste 
1051a85fe12eSEd Maste 	if (s->nocopy && s->buf == NULL)
1052a85fe12eSEd Maste 		return;
1053a85fe12eSEd Maste 
1054a85fe12eSEd Maste 	if ((id = elf_getdata(s->is, NULL)) == NULL) {
1055a85fe12eSEd Maste 		elferr = elf_errno();
1056a85fe12eSEd Maste 		if (elferr != 0)
1057a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata() failed: %s",
1058a85fe12eSEd Maste 			    elf_errmsg(elferr));
1059a85fe12eSEd Maste 		return;
1060a85fe12eSEd Maste 	}
1061a85fe12eSEd Maste 
1062a85fe12eSEd Maste 	if ((od = elf_newdata(s->os)) == NULL)
1063a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1064a85fe12eSEd Maste 		    elf_errmsg(-1));
1065a85fe12eSEd Maste 
1066a85fe12eSEd Maste 	if (s->nocopy) {
1067a85fe12eSEd Maste 		/* Use s->buf as content if s->nocopy is set. */
1068a85fe12eSEd Maste 		od->d_align	= id->d_align;
1069a85fe12eSEd Maste 		od->d_off	= 0;
1070a85fe12eSEd Maste 		od->d_buf	= s->buf;
1071a85fe12eSEd Maste 		od->d_type	= id->d_type;
1072a85fe12eSEd Maste 		od->d_size	= s->sz;
1073a85fe12eSEd Maste 		od->d_version	= id->d_version;
1074a85fe12eSEd Maste 	} else {
1075a85fe12eSEd Maste 		od->d_align	= id->d_align;
1076a85fe12eSEd Maste 		od->d_off	= id->d_off;
1077a85fe12eSEd Maste 		od->d_buf	= id->d_buf;
1078a85fe12eSEd Maste 		od->d_type	= id->d_type;
1079a85fe12eSEd Maste 		od->d_size	= id->d_size;
1080a85fe12eSEd Maste 		od->d_version	= id->d_version;
1081a85fe12eSEd Maste 	}
10824a85c691SEd Maste 
10834a85c691SEd Maste 	/*
10844a85c691SEd Maste 	 * Alignment Fixup. libelf does not allow the alignment for
10854a85c691SEd Maste 	 * Elf_Data descriptor to be set to 0. In this case we workaround
10864a85c691SEd Maste 	 * it by setting the alignment to 1.
10874a85c691SEd Maste 	 *
10884a85c691SEd Maste 	 * According to the ELF ABI, alignment 0 and 1 has the same
10894a85c691SEd Maste 	 * meaning: the section has no alignment constraints.
10904a85c691SEd Maste 	 */
10914a85c691SEd Maste 	if (od->d_align == 0)
10924a85c691SEd Maste 		od->d_align = 1;
1093a85fe12eSEd Maste }
1094a85fe12eSEd Maste 
1095a85fe12eSEd Maste struct section *
1096a85fe12eSEd Maste create_external_section(struct elfcopy *ecp, const char *name, char *newname,
1097a85fe12eSEd Maste     void *buf, uint64_t size, uint64_t off, uint64_t stype, Elf_Type dtype,
1098a85fe12eSEd Maste     uint64_t flags, uint64_t align, uint64_t vma, int loadable)
1099a85fe12eSEd Maste {
1100a85fe12eSEd Maste 	struct section	*s;
1101a85fe12eSEd Maste 	Elf_Scn		*os;
1102a85fe12eSEd Maste 	Elf_Data	*od;
1103a85fe12eSEd Maste 	GElf_Shdr	 osh;
1104a85fe12eSEd Maste 
1105a85fe12eSEd Maste 	if ((os = elf_newscn(ecp->eout)) == NULL)
1106a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn() failed: %s",
1107a85fe12eSEd Maste 		    elf_errmsg(-1));
1108a85fe12eSEd Maste 	if ((s = calloc(1, sizeof(*s))) == NULL)
1109a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1110a85fe12eSEd Maste 	s->name = name;
1111a85fe12eSEd Maste 	s->newname = newname;	/* needs to be free()'ed */
1112a85fe12eSEd Maste 	s->off = off;
1113a85fe12eSEd Maste 	s->sz = size;
1114a85fe12eSEd Maste 	s->vma = vma;
1115a85fe12eSEd Maste 	s->align = align;
1116a85fe12eSEd Maste 	s->loadable = loadable;
1117a85fe12eSEd Maste 	s->is = NULL;
1118a85fe12eSEd Maste 	s->os = os;
1119a85fe12eSEd Maste 	s->type = stype;
1120a85fe12eSEd Maste 	s->nocopy = 1;
1121a85fe12eSEd Maste 	insert_to_sec_list(ecp, s, 1);
1122a85fe12eSEd Maste 
1123a85fe12eSEd Maste 	if (gelf_getshdr(os, &osh) == NULL)
1124a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
1125a85fe12eSEd Maste 		    elf_errmsg(-1));
1126a85fe12eSEd Maste 	osh.sh_flags = flags;
1127a85fe12eSEd Maste 	osh.sh_type = s->type;
1128a85fe12eSEd Maste 	osh.sh_addr = s->vma;
1129a85fe12eSEd Maste 	osh.sh_addralign = s->align;
1130a85fe12eSEd Maste 	if (!gelf_update_shdr(os, &osh))
1131a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1132a85fe12eSEd Maste 		    elf_errmsg(-1));
1133a85fe12eSEd Maste 	add_to_shstrtab(ecp, name);
1134a85fe12eSEd Maste 
1135a85fe12eSEd Maste 	if (buf != NULL && size != 0) {
1136a85fe12eSEd Maste 		if ((od = elf_newdata(os)) == NULL)
1137a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1138a85fe12eSEd Maste 			    elf_errmsg(-1));
1139a85fe12eSEd Maste 		od->d_align = align;
1140a85fe12eSEd Maste 		od->d_off = 0;
1141a85fe12eSEd Maste 		od->d_buf = buf;
1142a85fe12eSEd Maste 		od->d_size = size;
1143a85fe12eSEd Maste 		od->d_type = dtype;
1144a85fe12eSEd Maste 		od->d_version = EV_CURRENT;
1145a85fe12eSEd Maste 	}
1146a85fe12eSEd Maste 
1147a85fe12eSEd Maste 	/*
1148a85fe12eSEd Maste 	 * Clear SYMTAB_INTACT, as we probably need to update/add new
1149a85fe12eSEd Maste 	 * STT_SECTION symbols into the symbol table.
1150a85fe12eSEd Maste 	 */
1151a85fe12eSEd Maste 	ecp->flags &= ~SYMTAB_INTACT;
1152a85fe12eSEd Maste 
1153a85fe12eSEd Maste 	return (s);
1154a85fe12eSEd Maste }
1155a85fe12eSEd Maste 
1156a85fe12eSEd Maste /*
1157a85fe12eSEd Maste  * Insert sections specified by --add-section to the end of section list.
1158a85fe12eSEd Maste  */
1159a85fe12eSEd Maste static void
1160a85fe12eSEd Maste insert_sections(struct elfcopy *ecp)
1161a85fe12eSEd Maste {
1162a85fe12eSEd Maste 	struct sec_add	*sa;
1163a85fe12eSEd Maste 	struct section	*s;
1164a85fe12eSEd Maste 	size_t		 off;
1165a85fe12eSEd Maste 
1166a85fe12eSEd Maste 	/* Put these sections in the end of current list. */
1167a85fe12eSEd Maste 	off = 0;
1168a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1169a85fe12eSEd Maste 		if (s->type != SHT_NOBITS && s->type != SHT_NULL)
1170a85fe12eSEd Maste 			off = s->off + s->sz;
1171a85fe12eSEd Maste 		else
1172a85fe12eSEd Maste 			off = s->off;
1173a85fe12eSEd Maste 	}
1174a85fe12eSEd Maste 
1175a85fe12eSEd Maste 	STAILQ_FOREACH(sa, &ecp->v_sadd, sadd_list) {
1176a85fe12eSEd Maste 
1177a85fe12eSEd Maste 		/* TODO: Add section header vma/lma, flag changes here */
1178a85fe12eSEd Maste 
1179a85fe12eSEd Maste 		(void) create_external_section(ecp, sa->name, NULL, sa->content,
1180a85fe12eSEd Maste 		    sa->size, off, SHT_PROGBITS, ELF_T_BYTE, 0, 1, 0, 0);
1181a85fe12eSEd Maste 	}
1182a85fe12eSEd Maste }
1183a85fe12eSEd Maste 
1184a85fe12eSEd Maste void
1185a85fe12eSEd Maste add_to_shstrtab(struct elfcopy *ecp, const char *name)
1186a85fe12eSEd Maste {
1187a85fe12eSEd Maste 	struct section *s;
1188a85fe12eSEd Maste 
1189a85fe12eSEd Maste 	s = ecp->shstrtab;
1190a85fe12eSEd Maste 	insert_to_strtab(s, name);
1191a85fe12eSEd Maste }
1192a85fe12eSEd Maste 
1193a85fe12eSEd Maste void
1194a85fe12eSEd Maste update_shdr(struct elfcopy *ecp, int update_link)
1195a85fe12eSEd Maste {
1196a85fe12eSEd Maste 	struct section	*s;
1197a85fe12eSEd Maste 	GElf_Shdr	 osh;
1198a85fe12eSEd Maste 	int		 elferr;
1199a85fe12eSEd Maste 
1200a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
1201a85fe12eSEd Maste 		if (s->pseudo)
1202a85fe12eSEd Maste 			continue;
1203a85fe12eSEd Maste 
1204a85fe12eSEd Maste 		if (gelf_getshdr(s->os, &osh) == NULL)
1205a85fe12eSEd Maste 			errx(EXIT_FAILURE, "668 gelf_getshdr failed: %s",
1206a85fe12eSEd Maste 			    elf_errmsg(-1));
1207a85fe12eSEd Maste 
1208a85fe12eSEd Maste 		/* Find section name in string table and set sh_name. */
1209a85fe12eSEd Maste 		osh.sh_name = lookup_string(ecp->shstrtab, s->name);
1210a85fe12eSEd Maste 
1211a85fe12eSEd Maste 		/*
1212a85fe12eSEd Maste 		 * sh_link needs to be updated, since the index of the
1213a85fe12eSEd Maste 		 * linked section might have changed.
1214a85fe12eSEd Maste 		 */
1215a85fe12eSEd Maste 		if (update_link && osh.sh_link != 0)
1216a85fe12eSEd Maste 			osh.sh_link = ecp->secndx[osh.sh_link];
1217a85fe12eSEd Maste 
1218a85fe12eSEd Maste 		/*
1219a85fe12eSEd Maste 		 * sh_info of relocation section links to the section to which
1220a85fe12eSEd Maste 		 * its relocation info applies. So it may need update as well.
1221a85fe12eSEd Maste 		 */
1222a85fe12eSEd Maste 		if ((s->type == SHT_REL || s->type == SHT_RELA) &&
1223a85fe12eSEd Maste 		    osh.sh_info != 0)
1224a85fe12eSEd Maste 			osh.sh_info = ecp->secndx[osh.sh_info];
1225a85fe12eSEd Maste 
1226*b00fe64fSEd Maste 		/*
1227*b00fe64fSEd Maste 		 * sh_info of SHT_GROUP section needs to point to the correct
1228*b00fe64fSEd Maste 		 * string in the symbol table.
1229*b00fe64fSEd Maste 		 */
1230*b00fe64fSEd Maste 		if (s->type == SHT_GROUP && (ecp->flags & SYMTAB_EXIST) &&
1231*b00fe64fSEd Maste 		    (ecp->flags & SYMTAB_INTACT) == 0)
1232*b00fe64fSEd Maste 			osh.sh_info = ecp->symndx[osh.sh_info];
1233*b00fe64fSEd Maste 
1234a85fe12eSEd Maste 		if (!gelf_update_shdr(s->os, &osh))
1235a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1236a85fe12eSEd Maste 			    elf_errmsg(-1));
1237a85fe12eSEd Maste 	}
1238a85fe12eSEd Maste 	elferr = elf_errno();
1239a85fe12eSEd Maste 	if (elferr != 0)
1240a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
1241a85fe12eSEd Maste 		    elf_errmsg(elferr));
1242a85fe12eSEd Maste }
1243a85fe12eSEd Maste 
1244a85fe12eSEd Maste void
1245a85fe12eSEd Maste init_shstrtab(struct elfcopy *ecp)
1246a85fe12eSEd Maste {
1247a85fe12eSEd Maste 	struct section *s;
1248a85fe12eSEd Maste 
1249a85fe12eSEd Maste 	if ((ecp->shstrtab = calloc(1, sizeof(*ecp->shstrtab))) == NULL)
1250a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
1251a85fe12eSEd Maste 	s = ecp->shstrtab;
1252a85fe12eSEd Maste 	s->name = ".shstrtab";
1253a85fe12eSEd Maste 	s->is = NULL;
1254a85fe12eSEd Maste 	s->sz = 0;
1255a85fe12eSEd Maste 	s->align = 1;
1256a85fe12eSEd Maste 	s->loadable = 0;
1257a85fe12eSEd Maste 	s->type = SHT_STRTAB;
1258a85fe12eSEd Maste 	s->vma = 0;
12599ef62fdbSEd Maste 
12609ef62fdbSEd Maste 	insert_to_strtab(s, "");
12619ef62fdbSEd Maste 	insert_to_strtab(s, ".symtab");
12629ef62fdbSEd Maste 	insert_to_strtab(s, ".strtab");
12639ef62fdbSEd Maste 	insert_to_strtab(s, ".shstrtab");
1264a85fe12eSEd Maste }
1265a85fe12eSEd Maste 
1266a85fe12eSEd Maste void
1267a85fe12eSEd Maste set_shstrtab(struct elfcopy *ecp)
1268a85fe12eSEd Maste {
1269a85fe12eSEd Maste 	struct section	*s;
1270a85fe12eSEd Maste 	Elf_Data	*data;
1271a85fe12eSEd Maste 	GElf_Shdr	 sh;
1272a85fe12eSEd Maste 
1273a85fe12eSEd Maste 	s = ecp->shstrtab;
1274a85fe12eSEd Maste 
1275a85fe12eSEd Maste 	if (gelf_getshdr(s->os, &sh) == NULL)
1276a85fe12eSEd Maste 		errx(EXIT_FAILURE, "692 gelf_getshdr() failed: %s",
1277a85fe12eSEd Maste 		    elf_errmsg(-1));
1278a85fe12eSEd Maste 	sh.sh_addr	= 0;
1279a85fe12eSEd Maste 	sh.sh_addralign	= 1;
1280a85fe12eSEd Maste 	sh.sh_offset	= s->off;
1281a85fe12eSEd Maste 	sh.sh_type	= SHT_STRTAB;
1282a85fe12eSEd Maste 	sh.sh_flags	= 0;
1283a85fe12eSEd Maste 	sh.sh_entsize	= 0;
1284a85fe12eSEd Maste 	sh.sh_info	= 0;
1285a85fe12eSEd Maste 	sh.sh_link	= 0;
1286a85fe12eSEd Maste 
1287a85fe12eSEd Maste 	if ((data = elf_newdata(s->os)) == NULL)
1288a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s",
1289a85fe12eSEd Maste 		    elf_errmsg(-1));
1290a85fe12eSEd Maste 
1291a85fe12eSEd Maste 	/*
1292a85fe12eSEd Maste 	 * If we don't have a symbol table, skip those a few bytes
1293a85fe12eSEd Maste 	 * which are reserved for this in the beginning of shstrtab.
1294a85fe12eSEd Maste 	 */
1295a85fe12eSEd Maste 	if (!(ecp->flags & SYMTAB_EXIST)) {
1296a85fe12eSEd Maste 		s->sz -= sizeof(".symtab\0.strtab");
1297a85fe12eSEd Maste 		memmove(s->buf, (char *)s->buf + sizeof(".symtab\0.strtab"),
1298a85fe12eSEd Maste 		    s->sz);
1299a85fe12eSEd Maste 	}
1300a85fe12eSEd Maste 
1301a85fe12eSEd Maste 	sh.sh_size	= s->sz;
1302a85fe12eSEd Maste 	if (!gelf_update_shdr(s->os, &sh))
1303a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1304a85fe12eSEd Maste 		    elf_errmsg(-1));
1305a85fe12eSEd Maste 
1306a85fe12eSEd Maste 	data->d_align	= 1;
1307a85fe12eSEd Maste 	data->d_buf	= s->buf;
1308a85fe12eSEd Maste 	data->d_size	= s->sz;
1309a85fe12eSEd Maste 	data->d_off	= 0;
1310a85fe12eSEd Maste 	data->d_type	= ELF_T_BYTE;
1311a85fe12eSEd Maste 	data->d_version	= EV_CURRENT;
1312a85fe12eSEd Maste 
1313a85fe12eSEd Maste 	if (!elf_setshstrndx(ecp->eout, elf_ndxscn(s->os)))
1314a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_setshstrndx() failed: %s",
1315a85fe12eSEd Maste 		     elf_errmsg(-1));
1316a85fe12eSEd Maste }
1317a85fe12eSEd Maste 
1318a85fe12eSEd Maste void
1319a85fe12eSEd Maste add_section(struct elfcopy *ecp, const char *arg)
1320a85fe12eSEd Maste {
1321a85fe12eSEd Maste 	struct sec_add	*sa;
1322a85fe12eSEd Maste 	struct stat	 sb;
1323a85fe12eSEd Maste 	const char	*s, *fn;
1324a85fe12eSEd Maste 	FILE		*fp;
1325a85fe12eSEd Maste 	int		 len;
1326a85fe12eSEd Maste 
1327a85fe12eSEd Maste 	if ((s = strchr(arg, '=')) == NULL)
1328a85fe12eSEd Maste 		errx(EXIT_FAILURE,
1329a85fe12eSEd Maste 		    "illegal format for --add-section option");
1330a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1331a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1332a85fe12eSEd Maste 
1333a85fe12eSEd Maste 	len = s - arg;
1334a85fe12eSEd Maste 	if ((sa->name = malloc(len + 1)) == NULL)
1335a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1336a85fe12eSEd Maste 	strncpy(sa->name, arg, len);
1337a85fe12eSEd Maste 	sa->name[len] = '\0';
1338a85fe12eSEd Maste 
1339a85fe12eSEd Maste 	fn = s + 1;
1340a85fe12eSEd Maste 	if (stat(fn, &sb) == -1)
1341a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1342a85fe12eSEd Maste 	sa->size = sb.st_size;
1343a85fe12eSEd Maste 	if ((sa->content = malloc(sa->size)) == NULL)
1344a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1345a85fe12eSEd Maste 	if ((fp = fopen(fn, "r")) == NULL)
1346a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", fn);
1347a85fe12eSEd Maste 	if (fread(sa->content, 1, sa->size, fp) == 0 ||
1348a85fe12eSEd Maste 	    ferror(fp))
1349a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1350a85fe12eSEd Maste 	fclose(fp);
1351a85fe12eSEd Maste 
1352a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1353a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1354a85fe12eSEd Maste }
1355a85fe12eSEd Maste 
1356a85fe12eSEd Maste void
1357a85fe12eSEd Maste free_sec_add(struct elfcopy *ecp)
1358a85fe12eSEd Maste {
1359a85fe12eSEd Maste 	struct sec_add *sa, *sa_temp;
1360a85fe12eSEd Maste 
1361a85fe12eSEd Maste 	STAILQ_FOREACH_SAFE(sa, &ecp->v_sadd, sadd_list, sa_temp) {
1362a85fe12eSEd Maste 		STAILQ_REMOVE(&ecp->v_sadd, sa, sec_add, sadd_list);
1363a85fe12eSEd Maste 		free(sa->name);
1364a85fe12eSEd Maste 		free(sa->content);
1365a85fe12eSEd Maste 		free(sa);
1366a85fe12eSEd Maste 	}
1367a85fe12eSEd Maste }
1368a85fe12eSEd Maste 
1369a85fe12eSEd Maste static void
1370a85fe12eSEd Maste add_gnu_debuglink(struct elfcopy *ecp)
1371a85fe12eSEd Maste {
1372a85fe12eSEd Maste 	struct sec_add	*sa;
1373a85fe12eSEd Maste 	struct stat	 sb;
1374a85fe12eSEd Maste 	FILE		*fp;
1375a85fe12eSEd Maste 	char		*fnbase, *buf;
1376a85fe12eSEd Maste 	int		 crc_off;
1377a85fe12eSEd Maste 	int		 crc;
1378a85fe12eSEd Maste 
1379a85fe12eSEd Maste 	if (ecp->debuglink == NULL)
1380a85fe12eSEd Maste 		return;
1381a85fe12eSEd Maste 
1382a85fe12eSEd Maste 	/* Read debug file content. */
1383a85fe12eSEd Maste 	if ((sa = malloc(sizeof(*sa))) == NULL)
1384a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1385a85fe12eSEd Maste 	if ((sa->name = strdup(".gnu_debuglink")) == NULL)
1386a85fe12eSEd Maste 		err(EXIT_FAILURE, "strdup failed");
1387a85fe12eSEd Maste 	if (stat(ecp->debuglink, &sb) == -1)
1388a85fe12eSEd Maste 		err(EXIT_FAILURE, "stat failed");
1389a85fe12eSEd Maste 	if ((buf = malloc(sb.st_size)) == NULL)
1390a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1391a85fe12eSEd Maste 	if ((fp = fopen(ecp->debuglink, "r")) == NULL)
1392a85fe12eSEd Maste 		err(EXIT_FAILURE, "can not open %s", ecp->debuglink);
1393a85fe12eSEd Maste 	if (fread(buf, 1, sb.st_size, fp) == 0 ||
1394a85fe12eSEd Maste 	    ferror(fp))
1395a85fe12eSEd Maste 		err(EXIT_FAILURE, "fread failed");
1396a85fe12eSEd Maste 	fclose(fp);
1397a85fe12eSEd Maste 
1398a85fe12eSEd Maste 	/* Calculate crc checksum.  */
1399a85fe12eSEd Maste 	crc = calc_crc32(buf, sb.st_size, 0xFFFFFFFF);
1400a85fe12eSEd Maste 	free(buf);
1401a85fe12eSEd Maste 
1402a85fe12eSEd Maste 	/* Calculate section size and the offset to store crc checksum. */
1403a85fe12eSEd Maste 	if ((fnbase = basename(ecp->debuglink)) == NULL)
1404a85fe12eSEd Maste 		err(EXIT_FAILURE, "basename failed");
1405a85fe12eSEd Maste 	crc_off = roundup(strlen(fnbase) + 1, 4);
1406a85fe12eSEd Maste 	sa->size = crc_off + 4;
1407a85fe12eSEd Maste 
1408a85fe12eSEd Maste 	/* Section content. */
1409a85fe12eSEd Maste 	if ((sa->content = calloc(1, sa->size)) == NULL)
1410a85fe12eSEd Maste 		err(EXIT_FAILURE, "malloc failed");
1411a85fe12eSEd Maste 	strncpy(sa->content, fnbase, strlen(fnbase));
1412a85fe12eSEd Maste 	if (ecp->oed == ELFDATA2LSB) {
1413a85fe12eSEd Maste 		sa->content[crc_off] = crc & 0xFF;
1414a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 8) & 0xFF;
1415a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 16) & 0xFF;
1416a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc >> 24;
1417a85fe12eSEd Maste 	} else {
1418a85fe12eSEd Maste 		sa->content[crc_off] = crc >> 24;
1419a85fe12eSEd Maste 		sa->content[crc_off + 1] = (crc >> 16) & 0xFF;
1420a85fe12eSEd Maste 		sa->content[crc_off + 2] = (crc >> 8) & 0xFF;
1421a85fe12eSEd Maste 		sa->content[crc_off + 3] = crc & 0xFF;
1422a85fe12eSEd Maste 	}
1423a85fe12eSEd Maste 
1424a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_sadd, sa, sadd_list);
1425a85fe12eSEd Maste 	ecp->flags |= SEC_ADD;
1426a85fe12eSEd Maste }
1427a85fe12eSEd Maste 
1428a85fe12eSEd Maste static void
1429a85fe12eSEd Maste insert_to_strtab(struct section *t, const char *s)
1430a85fe12eSEd Maste {
1431a85fe12eSEd Maste 	const char	*r;
1432a85fe12eSEd Maste 	char		*b, *c;
1433a85fe12eSEd Maste 	size_t		 len, slen;
1434a85fe12eSEd Maste 	int		 append;
1435a85fe12eSEd Maste 
1436a85fe12eSEd Maste 	if (t->sz == 0) {
1437a85fe12eSEd Maste 		t->cap = 512;
1438a85fe12eSEd Maste 		if ((t->buf = malloc(t->cap)) == NULL)
1439a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");
1440a85fe12eSEd Maste 	}
1441a85fe12eSEd Maste 
1442a85fe12eSEd Maste 	slen = strlen(s);
1443a85fe12eSEd Maste 	append = 0;
1444a85fe12eSEd Maste 	b = t->buf;
1445a85fe12eSEd Maste 	for (c = b; c < b + t->sz;) {
1446a85fe12eSEd Maste 		len = strlen(c);
1447a85fe12eSEd Maste 		if (!append && len >= slen) {
1448a85fe12eSEd Maste 			r = c + (len - slen);
1449a85fe12eSEd Maste 			if (strcmp(r, s) == 0)
1450a85fe12eSEd Maste 				return;
1451a85fe12eSEd Maste 		} else if (len < slen && len != 0) {
1452a85fe12eSEd Maste 			r = s + (slen - len);
1453a85fe12eSEd Maste 			if (strcmp(c, r) == 0) {
1454a85fe12eSEd Maste 				t->sz -= len + 1;
1455a85fe12eSEd Maste 				memmove(c, c + len + 1, t->sz - (c - b));
1456a85fe12eSEd Maste 				append = 1;
1457a85fe12eSEd Maste 				continue;
1458a85fe12eSEd Maste 			}
1459a85fe12eSEd Maste 		}
1460a85fe12eSEd Maste 		c += len + 1;
1461a85fe12eSEd Maste 	}
1462a85fe12eSEd Maste 
1463a85fe12eSEd Maste 	while (t->sz + slen + 1 >= t->cap) {
1464a85fe12eSEd Maste 		t->cap *= 2;
1465a85fe12eSEd Maste 		if ((t->buf = realloc(t->buf, t->cap)) == NULL)
1466a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");
1467a85fe12eSEd Maste 	}
1468a85fe12eSEd Maste 	b = t->buf;
1469a85fe12eSEd Maste 	strncpy(&b[t->sz], s, slen);
1470a85fe12eSEd Maste 	b[t->sz + slen] = '\0';
1471a85fe12eSEd Maste 	t->sz += slen + 1;
1472a85fe12eSEd Maste }
1473a85fe12eSEd Maste 
1474a85fe12eSEd Maste static int
1475a85fe12eSEd Maste lookup_string(struct section *t, const char *s)
1476a85fe12eSEd Maste {
1477a85fe12eSEd Maste 	const char	*b, *c, *r;
1478a85fe12eSEd Maste 	size_t		 len, slen;
1479a85fe12eSEd Maste 
1480a85fe12eSEd Maste 	slen = strlen(s);
1481a85fe12eSEd Maste 	b = t->buf;
1482a85fe12eSEd Maste 	for (c = b; c < b + t->sz;) {
1483a85fe12eSEd Maste 		len = strlen(c);
1484a85fe12eSEd Maste 		if (len >= slen) {
1485a85fe12eSEd Maste 			r = c + (len - slen);
1486a85fe12eSEd Maste 			if (strcmp(r, s) == 0)
1487a85fe12eSEd Maste 				return (r - b);
1488a85fe12eSEd Maste 		}
1489a85fe12eSEd Maste 		c += len + 1;
1490a85fe12eSEd Maste 	}
1491a85fe12eSEd Maste 
1492a85fe12eSEd Maste 	return (-1);
1493a85fe12eSEd Maste }
1494a85fe12eSEd Maste 
1495a85fe12eSEd Maste static uint32_t crctable[256] =
1496a85fe12eSEd Maste {
1497a85fe12eSEd Maste 	0x00000000L, 0x77073096L, 0xEE0E612CL, 0x990951BAL,
1498a85fe12eSEd Maste 	0x076DC419L, 0x706AF48FL, 0xE963A535L, 0x9E6495A3L,
1499a85fe12eSEd Maste 	0x0EDB8832L, 0x79DCB8A4L, 0xE0D5E91EL, 0x97D2D988L,
1500a85fe12eSEd Maste 	0x09B64C2BL, 0x7EB17CBDL, 0xE7B82D07L, 0x90BF1D91L,
1501a85fe12eSEd Maste 	0x1DB71064L, 0x6AB020F2L, 0xF3B97148L, 0x84BE41DEL,
1502a85fe12eSEd Maste 	0x1ADAD47DL, 0x6DDDE4EBL, 0xF4D4B551L, 0x83D385C7L,
1503a85fe12eSEd Maste 	0x136C9856L, 0x646BA8C0L, 0xFD62F97AL, 0x8A65C9ECL,
1504a85fe12eSEd Maste 	0x14015C4FL, 0x63066CD9L, 0xFA0F3D63L, 0x8D080DF5L,
1505a85fe12eSEd Maste 	0x3B6E20C8L, 0x4C69105EL, 0xD56041E4L, 0xA2677172L,
1506a85fe12eSEd Maste 	0x3C03E4D1L, 0x4B04D447L, 0xD20D85FDL, 0xA50AB56BL,
1507a85fe12eSEd Maste 	0x35B5A8FAL, 0x42B2986CL, 0xDBBBC9D6L, 0xACBCF940L,
1508a85fe12eSEd Maste 	0x32D86CE3L, 0x45DF5C75L, 0xDCD60DCFL, 0xABD13D59L,
1509a85fe12eSEd Maste 	0x26D930ACL, 0x51DE003AL, 0xC8D75180L, 0xBFD06116L,
1510a85fe12eSEd Maste 	0x21B4F4B5L, 0x56B3C423L, 0xCFBA9599L, 0xB8BDA50FL,
1511a85fe12eSEd Maste 	0x2802B89EL, 0x5F058808L, 0xC60CD9B2L, 0xB10BE924L,
1512a85fe12eSEd Maste 	0x2F6F7C87L, 0x58684C11L, 0xC1611DABL, 0xB6662D3DL,
1513a85fe12eSEd Maste 	0x76DC4190L, 0x01DB7106L, 0x98D220BCL, 0xEFD5102AL,
1514a85fe12eSEd Maste 	0x71B18589L, 0x06B6B51FL, 0x9FBFE4A5L, 0xE8B8D433L,
1515a85fe12eSEd Maste 	0x7807C9A2L, 0x0F00F934L, 0x9609A88EL, 0xE10E9818L,
1516a85fe12eSEd Maste 	0x7F6A0DBBL, 0x086D3D2DL, 0x91646C97L, 0xE6635C01L,
1517a85fe12eSEd Maste 	0x6B6B51F4L, 0x1C6C6162L, 0x856530D8L, 0xF262004EL,
1518a85fe12eSEd Maste 	0x6C0695EDL, 0x1B01A57BL, 0x8208F4C1L, 0xF50FC457L,
1519a85fe12eSEd Maste 	0x65B0D9C6L, 0x12B7E950L, 0x8BBEB8EAL, 0xFCB9887CL,
1520a85fe12eSEd Maste 	0x62DD1DDFL, 0x15DA2D49L, 0x8CD37CF3L, 0xFBD44C65L,
1521a85fe12eSEd Maste 	0x4DB26158L, 0x3AB551CEL, 0xA3BC0074L, 0xD4BB30E2L,
1522a85fe12eSEd Maste 	0x4ADFA541L, 0x3DD895D7L, 0xA4D1C46DL, 0xD3D6F4FBL,
1523a85fe12eSEd Maste 	0x4369E96AL, 0x346ED9FCL, 0xAD678846L, 0xDA60B8D0L,
1524a85fe12eSEd Maste 	0x44042D73L, 0x33031DE5L, 0xAA0A4C5FL, 0xDD0D7CC9L,
1525a85fe12eSEd Maste 	0x5005713CL, 0x270241AAL, 0xBE0B1010L, 0xC90C2086L,
1526a85fe12eSEd Maste 	0x5768B525L, 0x206F85B3L, 0xB966D409L, 0xCE61E49FL,
1527a85fe12eSEd Maste 	0x5EDEF90EL, 0x29D9C998L, 0xB0D09822L, 0xC7D7A8B4L,
1528a85fe12eSEd Maste 	0x59B33D17L, 0x2EB40D81L, 0xB7BD5C3BL, 0xC0BA6CADL,
1529a85fe12eSEd Maste 	0xEDB88320L, 0x9ABFB3B6L, 0x03B6E20CL, 0x74B1D29AL,
1530a85fe12eSEd Maste 	0xEAD54739L, 0x9DD277AFL, 0x04DB2615L, 0x73DC1683L,
1531a85fe12eSEd Maste 	0xE3630B12L, 0x94643B84L, 0x0D6D6A3EL, 0x7A6A5AA8L,
1532a85fe12eSEd Maste 	0xE40ECF0BL, 0x9309FF9DL, 0x0A00AE27L, 0x7D079EB1L,
1533a85fe12eSEd Maste 	0xF00F9344L, 0x8708A3D2L, 0x1E01F268L, 0x6906C2FEL,
1534a85fe12eSEd Maste 	0xF762575DL, 0x806567CBL, 0x196C3671L, 0x6E6B06E7L,
1535a85fe12eSEd Maste 	0xFED41B76L, 0x89D32BE0L, 0x10DA7A5AL, 0x67DD4ACCL,
1536a85fe12eSEd Maste 	0xF9B9DF6FL, 0x8EBEEFF9L, 0x17B7BE43L, 0x60B08ED5L,
1537a85fe12eSEd Maste 	0xD6D6A3E8L, 0xA1D1937EL, 0x38D8C2C4L, 0x4FDFF252L,
1538a85fe12eSEd Maste 	0xD1BB67F1L, 0xA6BC5767L, 0x3FB506DDL, 0x48B2364BL,
1539a85fe12eSEd Maste 	0xD80D2BDAL, 0xAF0A1B4CL, 0x36034AF6L, 0x41047A60L,
1540a85fe12eSEd Maste 	0xDF60EFC3L, 0xA867DF55L, 0x316E8EEFL, 0x4669BE79L,
1541a85fe12eSEd Maste 	0xCB61B38CL, 0xBC66831AL, 0x256FD2A0L, 0x5268E236L,
1542a85fe12eSEd Maste 	0xCC0C7795L, 0xBB0B4703L, 0x220216B9L, 0x5505262FL,
1543a85fe12eSEd Maste 	0xC5BA3BBEL, 0xB2BD0B28L, 0x2BB45A92L, 0x5CB36A04L,
1544a85fe12eSEd Maste 	0xC2D7FFA7L, 0xB5D0CF31L, 0x2CD99E8BL, 0x5BDEAE1DL,
1545a85fe12eSEd Maste 	0x9B64C2B0L, 0xEC63F226L, 0x756AA39CL, 0x026D930AL,
1546a85fe12eSEd Maste 	0x9C0906A9L, 0xEB0E363FL, 0x72076785L, 0x05005713L,
1547a85fe12eSEd Maste 	0x95BF4A82L, 0xE2B87A14L, 0x7BB12BAEL, 0x0CB61B38L,
1548a85fe12eSEd Maste 	0x92D28E9BL, 0xE5D5BE0DL, 0x7CDCEFB7L, 0x0BDBDF21L,
1549a85fe12eSEd Maste 	0x86D3D2D4L, 0xF1D4E242L, 0x68DDB3F8L, 0x1FDA836EL,
1550a85fe12eSEd Maste 	0x81BE16CDL, 0xF6B9265BL, 0x6FB077E1L, 0x18B74777L,
1551a85fe12eSEd Maste 	0x88085AE6L, 0xFF0F6A70L, 0x66063BCAL, 0x11010B5CL,
1552a85fe12eSEd Maste 	0x8F659EFFL, 0xF862AE69L, 0x616BFFD3L, 0x166CCF45L,
1553a85fe12eSEd Maste 	0xA00AE278L, 0xD70DD2EEL, 0x4E048354L, 0x3903B3C2L,
1554a85fe12eSEd Maste 	0xA7672661L, 0xD06016F7L, 0x4969474DL, 0x3E6E77DBL,
1555a85fe12eSEd Maste 	0xAED16A4AL, 0xD9D65ADCL, 0x40DF0B66L, 0x37D83BF0L,
1556a85fe12eSEd Maste 	0xA9BCAE53L, 0xDEBB9EC5L, 0x47B2CF7FL, 0x30B5FFE9L,
1557a85fe12eSEd Maste 	0xBDBDF21CL, 0xCABAC28AL, 0x53B39330L, 0x24B4A3A6L,
1558a85fe12eSEd Maste 	0xBAD03605L, 0xCDD70693L, 0x54DE5729L, 0x23D967BFL,
1559a85fe12eSEd Maste 	0xB3667A2EL, 0xC4614AB8L, 0x5D681B02L, 0x2A6F2B94L,
1560a85fe12eSEd Maste 	0xB40BBE37L, 0xC30C8EA1L, 0x5A05DF1BL, 0x2D02EF8DL
1561a85fe12eSEd Maste };
1562a85fe12eSEd Maste 
1563a85fe12eSEd Maste static uint32_t
1564a85fe12eSEd Maste calc_crc32(const char *p, size_t len, uint32_t crc)
1565a85fe12eSEd Maste {
1566a85fe12eSEd Maste 	uint32_t i;
1567a85fe12eSEd Maste 
1568a85fe12eSEd Maste 	for (i = 0; i < len; i++) {
1569a85fe12eSEd Maste 		crc = crctable[(crc ^ *p++) & 0xFFL] ^ (crc >> 8);
1570a85fe12eSEd Maste 	}
1571a85fe12eSEd Maste 
1572a85fe12eSEd Maste 	return (crc ^ 0xFFFFFFFF);
1573a85fe12eSEd Maste }
1574