xref: /freebsd/contrib/elftoolchain/elfcopy/symbols.c (revision b00fe64f4acfe315181f65999af16e9a7bdc600b)
1a85fe12eSEd Maste /*-
2a85fe12eSEd Maste  * Copyright (c) 2007-2013 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 <err.h>
29a85fe12eSEd Maste #include <fnmatch.h>
30a85fe12eSEd Maste #include <stdio.h>
31a85fe12eSEd Maste #include <stdlib.h>
32a85fe12eSEd Maste #include <string.h>
33a85fe12eSEd Maste 
34a85fe12eSEd Maste #include "elfcopy.h"
35a85fe12eSEd Maste 
36*b00fe64fSEd Maste ELFTC_VCSID("$Id: symbols.c 3191 2015-05-04 17:07:01Z jkoshy $");
37a85fe12eSEd Maste 
38a85fe12eSEd Maste /* Symbol table buffer structure. */
39a85fe12eSEd Maste struct symbuf {
40a85fe12eSEd Maste 	Elf32_Sym *l32;		/* 32bit local symbol */
41a85fe12eSEd Maste 	Elf32_Sym *g32;		/* 32bit global symbol */
42a85fe12eSEd Maste 	Elf64_Sym *l64;		/* 64bit local symbol */
43a85fe12eSEd Maste 	Elf64_Sym *g64;		/* 64bit global symbol */
44a85fe12eSEd Maste 	size_t ngs, nls;	/* number of each kind */
45a85fe12eSEd Maste 	size_t gcap, lcap; 	/* buffer capacities. */
46a85fe12eSEd Maste };
47a85fe12eSEd Maste 
484a85c691SEd Maste struct sthash {
494a85c691SEd Maste 	LIST_ENTRY(sthash) sh_next;
504a85c691SEd Maste 	size_t sh_off;
514a85c691SEd Maste };
524a85c691SEd Maste typedef LIST_HEAD(,sthash) hash_head;
534a85c691SEd Maste #define STHASHSIZE 65536
544a85c691SEd Maste 
554a85c691SEd Maste struct strimpl {
564a85c691SEd Maste 	char *buf;		/* string table */
574a85c691SEd Maste 	size_t sz;		/* entries */
584a85c691SEd Maste 	size_t cap;		/* buffer capacity */
594a85c691SEd Maste 	hash_head hash[STHASHSIZE];
604a85c691SEd Maste };
614a85c691SEd Maste 
624a85c691SEd Maste 
63a85fe12eSEd Maste /* String table buffer structure. */
64a85fe12eSEd Maste struct strbuf {
654a85c691SEd Maste 	struct strimpl l;	/* local symbols */
664a85c691SEd Maste 	struct strimpl g;	/* global symbols */
67a85fe12eSEd Maste };
68a85fe12eSEd Maste 
69a85fe12eSEd Maste static int	is_debug_symbol(unsigned char st_info);
70a85fe12eSEd Maste static int	is_global_symbol(unsigned char st_info);
71a85fe12eSEd Maste static int	is_local_symbol(unsigned char st_info);
72a85fe12eSEd Maste static int	is_local_label(const char *name);
73a85fe12eSEd Maste static int	is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s);
74a85fe12eSEd Maste static int	is_remove_symbol(struct elfcopy *ecp, size_t sc, int i,
75a85fe12eSEd Maste 		    GElf_Sym *s, const char *name);
76a85fe12eSEd Maste static int	is_weak_symbol(unsigned char st_info);
774a85c691SEd Maste static int	lookup_exact_string(hash_head *hash, const char *buf,
784a85c691SEd Maste 		    const char *s);
79a85fe12eSEd Maste static int	generate_symbols(struct elfcopy *ecp);
80a85fe12eSEd Maste static void	mark_symbols(struct elfcopy *ecp, size_t sc);
81a85fe12eSEd Maste static int	match_wildcard(const char *name, const char *pattern);
824a85c691SEd Maste uint32_t	str_hash(const char *s);
83a85fe12eSEd Maste 
84a85fe12eSEd Maste /* Convenient bit vector operation macros. */
85a85fe12eSEd Maste #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))
86a85fe12eSEd Maste #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))
87a85fe12eSEd Maste #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))
88a85fe12eSEd Maste 
89a85fe12eSEd Maste static int
90a85fe12eSEd Maste is_debug_symbol(unsigned char st_info)
91a85fe12eSEd Maste {
92a85fe12eSEd Maste 
93a85fe12eSEd Maste 	if (GELF_ST_TYPE(st_info) == STT_SECTION ||
94a85fe12eSEd Maste 	    GELF_ST_TYPE(st_info) == STT_FILE)
95a85fe12eSEd Maste 		return (1);
96a85fe12eSEd Maste 
97a85fe12eSEd Maste 	return (0);
98a85fe12eSEd Maste }
99a85fe12eSEd Maste 
100a85fe12eSEd Maste static int
101a85fe12eSEd Maste is_global_symbol(unsigned char st_info)
102a85fe12eSEd Maste {
103a85fe12eSEd Maste 
104a85fe12eSEd Maste 	if (GELF_ST_BIND(st_info) == STB_GLOBAL)
105a85fe12eSEd Maste 		return (1);
106a85fe12eSEd Maste 
107a85fe12eSEd Maste 	return (0);
108a85fe12eSEd Maste }
109a85fe12eSEd Maste 
110a85fe12eSEd Maste static int
111a85fe12eSEd Maste is_weak_symbol(unsigned char st_info)
112a85fe12eSEd Maste {
113a85fe12eSEd Maste 
114a85fe12eSEd Maste 	if (GELF_ST_BIND(st_info) == STB_WEAK)
115a85fe12eSEd Maste 		return (1);
116a85fe12eSEd Maste 
117a85fe12eSEd Maste 	return (0);
118a85fe12eSEd Maste }
119a85fe12eSEd Maste 
120a85fe12eSEd Maste static int
121a85fe12eSEd Maste is_local_symbol(unsigned char st_info)
122a85fe12eSEd Maste {
123a85fe12eSEd Maste 
124a85fe12eSEd Maste 	if (GELF_ST_BIND(st_info) == STB_LOCAL)
125a85fe12eSEd Maste 		return (1);
126a85fe12eSEd Maste 
127a85fe12eSEd Maste 	return (0);
128a85fe12eSEd Maste }
129a85fe12eSEd Maste 
130a85fe12eSEd Maste static int
13167d97fe7SEd Maste is_hidden_symbol(unsigned char st_other)
13267d97fe7SEd Maste {
13367d97fe7SEd Maste 
13467d97fe7SEd Maste 	if (GELF_ST_VISIBILITY(st_other) == STV_HIDDEN ||
13567d97fe7SEd Maste 	    GELF_ST_VISIBILITY(st_other) == STV_INTERNAL)
13667d97fe7SEd Maste 		return (1);
13767d97fe7SEd Maste 
13867d97fe7SEd Maste 	return (0);
13967d97fe7SEd Maste }
14067d97fe7SEd Maste 
14167d97fe7SEd Maste static int
142a85fe12eSEd Maste is_local_label(const char *name)
143a85fe12eSEd Maste {
144a85fe12eSEd Maste 
145a85fe12eSEd Maste 	/* Compiler generated local symbols that start with .L */
146a85fe12eSEd Maste 	if (name[0] == '.' && name[1] == 'L')
147a85fe12eSEd Maste 		return (1);
148a85fe12eSEd Maste 
149a85fe12eSEd Maste 	return (0);
150a85fe12eSEd Maste }
151a85fe12eSEd Maste 
152a85fe12eSEd Maste /*
153a85fe12eSEd Maste  * Symbols related to relocation are needed.
154a85fe12eSEd Maste  */
155a85fe12eSEd Maste static int
156a85fe12eSEd Maste is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s)
157a85fe12eSEd Maste {
158a85fe12eSEd Maste 
159a85fe12eSEd Maste 	/* If symbol involves relocation, it is needed. */
160a85fe12eSEd Maste 	if (BIT_ISSET(ecp->v_rel, i))
161a85fe12eSEd Maste 		return (1);
162a85fe12eSEd Maste 
163a85fe12eSEd Maste 	/*
164a85fe12eSEd Maste 	 * For relocatable files (.o files), global and weak symbols
165a85fe12eSEd Maste 	 * are needed.
166a85fe12eSEd Maste 	 */
167a85fe12eSEd Maste 	if (ecp->flags & RELOCATABLE) {
168a85fe12eSEd Maste 		if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info))
169a85fe12eSEd Maste 			return (1);
170a85fe12eSEd Maste 	}
171a85fe12eSEd Maste 
172a85fe12eSEd Maste 	return (0);
173a85fe12eSEd Maste }
174a85fe12eSEd Maste 
175a85fe12eSEd Maste static int
176a85fe12eSEd Maste is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s,
177a85fe12eSEd Maste     const char *name)
178a85fe12eSEd Maste {
179a85fe12eSEd Maste 	GElf_Sym sym0 = {
180a85fe12eSEd Maste 		0, 		/* st_name */
181a85fe12eSEd Maste 		0,		/* st_value */
182a85fe12eSEd Maste 		0,		/* st_size */
183a85fe12eSEd Maste 		0,		/* st_info */
184a85fe12eSEd Maste 		0,		/* st_other */
185a85fe12eSEd Maste 		SHN_UNDEF,	/* st_shndx */
186a85fe12eSEd Maste 	};
187a85fe12eSEd Maste 
188a85fe12eSEd Maste 	if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
189a85fe12eSEd Maste 		return (0);
190a85fe12eSEd Maste 
191a85fe12eSEd Maste 	if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL)
192a85fe12eSEd Maste 		return (1);
193a85fe12eSEd Maste 
194a85fe12eSEd Maste 	/*
195a85fe12eSEd Maste 	 * Keep the first symbol if it is the special reserved symbol.
196a85fe12eSEd Maste 	 * XXX Should we generate one if it's missing?
197a85fe12eSEd Maste 	 */
198a85fe12eSEd Maste 	if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym)))
199a85fe12eSEd Maste 		return (0);
200a85fe12eSEd Maste 
201a85fe12eSEd Maste 	/* Remove the symbol if the section it refers to was removed. */
202a85fe12eSEd Maste 	if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE &&
203a85fe12eSEd Maste 	    ecp->secndx[s->st_shndx] == 0)
204a85fe12eSEd Maste 		return (1);
205a85fe12eSEd Maste 
206a85fe12eSEd Maste 	if (ecp->strip == STRIP_ALL)
207a85fe12eSEd Maste 		return (1);
208a85fe12eSEd Maste 
209a85fe12eSEd Maste 	if (ecp->v_rel == NULL)
210a85fe12eSEd Maste 		mark_symbols(ecp, sc);
211a85fe12eSEd Maste 
212a85fe12eSEd Maste 	if (is_needed_symbol(ecp, i, s))
213a85fe12eSEd Maste 		return (0);
214a85fe12eSEd Maste 
215a85fe12eSEd Maste 	if (ecp->strip == STRIP_UNNEEDED)
216a85fe12eSEd Maste 		return (1);
217a85fe12eSEd Maste 
218a85fe12eSEd Maste 	if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) &&
219a85fe12eSEd Maste 	    !is_debug_symbol(s->st_info))
220a85fe12eSEd Maste 		return (1);
221a85fe12eSEd Maste 
222a85fe12eSEd Maste 	if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) &&
223a85fe12eSEd Maste 	    !is_debug_symbol(s->st_info) && is_local_label(name))
224a85fe12eSEd Maste 		return (1);
225a85fe12eSEd Maste 
226a85fe12eSEd Maste 	if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info))
227a85fe12eSEd Maste 		return (1);
228a85fe12eSEd Maste 
229a85fe12eSEd Maste 	return (0);
230a85fe12eSEd Maste }
231a85fe12eSEd Maste 
232a85fe12eSEd Maste /*
233a85fe12eSEd Maste  * Mark symbols refered by relocation entries.
234a85fe12eSEd Maste  */
235a85fe12eSEd Maste static void
236a85fe12eSEd Maste mark_symbols(struct elfcopy *ecp, size_t sc)
237a85fe12eSEd Maste {
238a85fe12eSEd Maste 	const char	*name;
239a85fe12eSEd Maste 	Elf_Data	*d;
240a85fe12eSEd Maste 	Elf_Scn		*s;
241a85fe12eSEd Maste 	GElf_Rel	 r;
242a85fe12eSEd Maste 	GElf_Rela	 ra;
243a85fe12eSEd Maste 	GElf_Shdr	 sh;
244a85fe12eSEd Maste 	size_t		 n, indx;
245a85fe12eSEd Maste 	int		 elferr, i, len;
246a85fe12eSEd Maste 
247a85fe12eSEd Maste 	ecp->v_rel = calloc((sc + 7) / 8, 1);
248a85fe12eSEd Maste 	if (ecp->v_rel == NULL)
249a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
250a85fe12eSEd Maste 
251a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
252a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
253a85fe12eSEd Maste 		    elf_errmsg(-1));
254a85fe12eSEd Maste 
255a85fe12eSEd Maste 	s = NULL;
256a85fe12eSEd Maste 	while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
257a85fe12eSEd Maste 		if (gelf_getshdr(s, &sh) != &sh)
258a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
259a85fe12eSEd Maste 			    elf_errmsg(-1));
260a85fe12eSEd Maste 
261a85fe12eSEd Maste 		if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA)
262a85fe12eSEd Maste 			continue;
263a85fe12eSEd Maste 
264a85fe12eSEd Maste 		/*
265a85fe12eSEd Maste 		 * Skip if this reloc section won't appear in the
266a85fe12eSEd Maste 		 * output object.
267a85fe12eSEd Maste 		 */
268a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
269a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
270a85fe12eSEd Maste 			    elf_errmsg(-1));
271a85fe12eSEd Maste 		if (is_remove_section(ecp, name) ||
272a85fe12eSEd Maste 		    is_remove_reloc_sec(ecp, sh.sh_info))
273a85fe12eSEd Maste 			continue;
274a85fe12eSEd Maste 
275a85fe12eSEd Maste 		/* Skip if it's not for .symtab */
276a85fe12eSEd Maste 		if (sh.sh_link != elf_ndxscn(ecp->symtab->is))
277a85fe12eSEd Maste 			continue;
278a85fe12eSEd Maste 
279a85fe12eSEd Maste 		d = NULL;
280a85fe12eSEd Maste 		n = 0;
281a85fe12eSEd Maste 		while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) {
282a85fe12eSEd Maste 			len = d->d_size / sh.sh_entsize;
283a85fe12eSEd Maste 			for (i = 0; i < len; i++) {
284a85fe12eSEd Maste 				if (sh.sh_type == SHT_REL) {
285a85fe12eSEd Maste 					if (gelf_getrel(d, i, &r) != &r)
286a85fe12eSEd Maste 						errx(EXIT_FAILURE,
287a85fe12eSEd Maste 						    "elf_getrel failed: %s",
288a85fe12eSEd Maste 						     elf_errmsg(-1));
289a85fe12eSEd Maste 					n = GELF_R_SYM(r.r_info);
290a85fe12eSEd Maste 				} else {
291a85fe12eSEd Maste 					if (gelf_getrela(d, i, &ra) != &ra)
292a85fe12eSEd Maste 						errx(EXIT_FAILURE,
293a85fe12eSEd Maste 						    "elf_getrela failed: %s",
294a85fe12eSEd Maste 						     elf_errmsg(-1));
295a85fe12eSEd Maste 					n = GELF_R_SYM(ra.r_info);
296a85fe12eSEd Maste 				}
297a85fe12eSEd Maste 				if (n > 0 && n < sc)
298a85fe12eSEd Maste 					BIT_SET(ecp->v_rel, n);
299a85fe12eSEd Maste 				else if (n != 0)
300a85fe12eSEd Maste 					warnx("invalid symbox index");
301a85fe12eSEd Maste 			}
302a85fe12eSEd Maste 		}
303a85fe12eSEd Maste 		elferr = elf_errno();
304a85fe12eSEd Maste 		if (elferr != 0)
305a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getdata failed: %s",
306a85fe12eSEd Maste 			    elf_errmsg(elferr));
307a85fe12eSEd Maste 	}
308a85fe12eSEd Maste 	elferr = elf_errno();
309a85fe12eSEd Maste 	if (elferr != 0)
310a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
311a85fe12eSEd Maste 		    elf_errmsg(elferr));
312a85fe12eSEd Maste }
313a85fe12eSEd Maste 
314a85fe12eSEd Maste static int
315a85fe12eSEd Maste generate_symbols(struct elfcopy *ecp)
316a85fe12eSEd Maste {
317a85fe12eSEd Maste 	struct section	*s;
318a85fe12eSEd Maste 	struct symop	*sp;
319a85fe12eSEd Maste 	struct symbuf	*sy_buf;
320a85fe12eSEd Maste 	struct strbuf	*st_buf;
321a85fe12eSEd Maste 	const char	*name;
322a85fe12eSEd Maste 	char		*newname;
323a85fe12eSEd Maste 	unsigned char	*gsym;
324a85fe12eSEd Maste 	GElf_Shdr	 ish;
325a85fe12eSEd Maste 	GElf_Sym	 sym;
326a85fe12eSEd Maste 	Elf_Data*	 id;
327a85fe12eSEd Maste 	Elf_Scn		*is;
328cf781b2eSEd Maste 	size_t		 ishstrndx, namelen, ndx, sc, symndx;
329a85fe12eSEd Maste 	int		 ec, elferr, i;
330a85fe12eSEd Maste 
331a85fe12eSEd Maste 	if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0)
332a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
333a85fe12eSEd Maste 		    elf_errmsg(-1));
334a85fe12eSEd Maste 	if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE)
335a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getclass failed: %s",
336a85fe12eSEd Maste 		    elf_errmsg(-1));
337a85fe12eSEd Maste 
338a85fe12eSEd Maste 	/* Create buffers for .symtab and .strtab. */
339a85fe12eSEd Maste 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
340a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
341a85fe12eSEd Maste 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
342a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
343a85fe12eSEd Maste 	sy_buf->gcap = sy_buf->lcap = 64;
3444a85c691SEd Maste 	st_buf->g.cap = 256;
3454a85c691SEd Maste 	st_buf->l.cap = 64;
3464a85c691SEd Maste 	st_buf->l.sz = 1;	/* '\0' at start. */
3474a85c691SEd Maste 	st_buf->g.sz = 0;
348a85fe12eSEd Maste 
349a85fe12eSEd Maste 	ecp->symtab->sz = 0;
350a85fe12eSEd Maste 	ecp->strtab->sz = 0;
351a85fe12eSEd Maste 	ecp->symtab->buf = sy_buf;
352a85fe12eSEd Maste 	ecp->strtab->buf = st_buf;
353a85fe12eSEd Maste 
354a85fe12eSEd Maste 	/*
355a85fe12eSEd Maste 	 * Create bit vector v_secsym, which is used to mark sections
356a85fe12eSEd Maste 	 * that already have corresponding STT_SECTION symbols.
357a85fe12eSEd Maste 	 */
358a85fe12eSEd Maste 	ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
359a85fe12eSEd Maste 	if (ecp->v_secsym == NULL)
360a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
361a85fe12eSEd Maste 
362a85fe12eSEd Maste 	/* Locate .strtab of input object. */
363a85fe12eSEd Maste 	symndx = 0;
364a85fe12eSEd Maste 	name = NULL;
365a85fe12eSEd Maste 	is = NULL;
366a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
367a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) != &ish)
368a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
369a85fe12eSEd Maste 			    elf_errmsg(-1));
370a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
371a85fe12eSEd Maste 		    NULL)
372a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
373a85fe12eSEd Maste 			    elf_errmsg(-1));
374a85fe12eSEd Maste 		if (strcmp(name, ".strtab") == 0) {
375a85fe12eSEd Maste 			symndx = elf_ndxscn(is);
376a85fe12eSEd Maste 			break;
377a85fe12eSEd Maste 		}
378a85fe12eSEd Maste 	}
379a85fe12eSEd Maste 	elferr = elf_errno();
380a85fe12eSEd Maste 	if (elferr != 0)
381a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
382a85fe12eSEd Maste 		    elf_errmsg(elferr));
383a85fe12eSEd Maste 
384a85fe12eSEd Maste 	/* Symbol table should exist if this function is called. */
385a85fe12eSEd Maste 	if (symndx == 0) {
386a85fe12eSEd Maste 		warnx("can't find .strtab section");
387a85fe12eSEd Maste 		return (0);
388a85fe12eSEd Maste 	}
389a85fe12eSEd Maste 
390a85fe12eSEd Maste 	/* Locate .symtab of input object. */
391a85fe12eSEd Maste 	is = NULL;
392a85fe12eSEd Maste 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
393a85fe12eSEd Maste 		if (gelf_getshdr(is, &ish) != &ish)
394a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
395a85fe12eSEd Maste 			    elf_errmsg(-1));
396a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
397a85fe12eSEd Maste 		    NULL)
398a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
399a85fe12eSEd Maste 			    elf_errmsg(-1));
400a85fe12eSEd Maste 		if (strcmp(name, ".symtab") == 0)
401a85fe12eSEd Maste 			break;
402a85fe12eSEd Maste 	}
403a85fe12eSEd Maste 	elferr = elf_errno();
404a85fe12eSEd Maste 	if (elferr != 0)
405a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
406a85fe12eSEd Maste 		    elf_errmsg(elferr));
407a85fe12eSEd Maste 	if (is == NULL)
408a85fe12eSEd Maste 		errx(EXIT_FAILURE, "can't find .strtab section");
409a85fe12eSEd Maste 
410a85fe12eSEd Maste 	/*
411a85fe12eSEd Maste 	 * Create bit vector gsym to mark global symbols, and symndx
412a85fe12eSEd Maste 	 * to keep track of symbol index changes from input object to
413a85fe12eSEd Maste 	 * output object, it is used by update_reloc() later to update
414a85fe12eSEd Maste 	 * relocation information.
415a85fe12eSEd Maste 	 */
416a85fe12eSEd Maste 	gsym = NULL;
417a85fe12eSEd Maste 	sc = ish.sh_size / ish.sh_entsize;
418a85fe12eSEd Maste 	if (sc > 0) {
419a85fe12eSEd Maste 		ecp->symndx = calloc(sc, sizeof(*ecp->symndx));
420a85fe12eSEd Maste 		if (ecp->symndx == NULL)
421a85fe12eSEd Maste 			err(EXIT_FAILURE, "calloc failed");
422a85fe12eSEd Maste 		gsym = calloc((sc + 7) / 8, sizeof(*gsym));
423a85fe12eSEd Maste 		if (gsym == NULL)
424a85fe12eSEd Maste 			err(EXIT_FAILURE, "calloc failed");
425a85fe12eSEd Maste 		if ((id = elf_getdata(is, NULL)) == NULL) {
426a85fe12eSEd Maste 			elferr = elf_errno();
427a85fe12eSEd Maste 			if (elferr != 0)
428a85fe12eSEd Maste 				errx(EXIT_FAILURE, "elf_getdata failed: %s",
429a85fe12eSEd Maste 				    elf_errmsg(elferr));
430a85fe12eSEd Maste 			return (0);
431a85fe12eSEd Maste 		}
432a85fe12eSEd Maste 	} else
433a85fe12eSEd Maste 		return (0);
434a85fe12eSEd Maste 
435a85fe12eSEd Maste 	/* Copy/Filter each symbol. */
436a85fe12eSEd Maste 	for (i = 0; (size_t)i < sc; i++) {
437a85fe12eSEd Maste 		if (gelf_getsym(id, i, &sym) != &sym)
438a85fe12eSEd Maste 			errx(EXIT_FAILURE, "gelf_getsym failed: %s",
439a85fe12eSEd Maste 			    elf_errmsg(-1));
440a85fe12eSEd Maste 		if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
441a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
442a85fe12eSEd Maste 			    elf_errmsg(-1));
443a85fe12eSEd Maste 
444a85fe12eSEd Maste 		/* Symbol filtering. */
445a85fe12eSEd Maste 		if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
446a85fe12eSEd Maste 			continue;
447a85fe12eSEd Maste 
448a85fe12eSEd Maste 		/* Check if we need to change the binding of this symbol. */
449a85fe12eSEd Maste 		if (is_global_symbol(sym.st_info) ||
450a85fe12eSEd Maste 		    is_weak_symbol(sym.st_info)) {
451a85fe12eSEd Maste 			/*
452a85fe12eSEd Maste 			 * XXX Binutils objcopy does not weaken certain
453a85fe12eSEd Maste 			 * symbols.
454a85fe12eSEd Maste 			 */
455a85fe12eSEd Maste 			if (ecp->flags & WEAKEN_ALL ||
456a85fe12eSEd Maste 			    lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL)
457a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_WEAK,
458a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
459a85fe12eSEd Maste 			/* Do not localize undefined symbols. */
460a85fe12eSEd Maste 			if (sym.st_shndx != SHN_UNDEF &&
461a85fe12eSEd Maste 			    lookup_symop_list(ecp, name, SYMOP_LOCALIZE) !=
462a85fe12eSEd Maste 			    NULL)
463a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
464a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
465a85fe12eSEd Maste 			if (ecp->flags & KEEP_GLOBAL &&
466a85fe12eSEd Maste 			    sym.st_shndx != SHN_UNDEF &&
467a85fe12eSEd Maste 			    lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL)
468a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
469a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
47067d97fe7SEd Maste 			if (ecp->flags & LOCALIZE_HIDDEN &&
47167d97fe7SEd Maste 			    sym.st_shndx != SHN_UNDEF &&
47267d97fe7SEd Maste 			    is_hidden_symbol(sym.st_other))
47367d97fe7SEd Maste 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
47467d97fe7SEd Maste 				    GELF_ST_TYPE(sym.st_info));
475a85fe12eSEd Maste 		} else {
476a85fe12eSEd Maste 			/* STB_LOCAL binding. */
477a85fe12eSEd Maste 			if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
478a85fe12eSEd Maste 			    NULL)
479a85fe12eSEd Maste 				sym.st_info = GELF_ST_INFO(STB_GLOBAL,
480a85fe12eSEd Maste 				    GELF_ST_TYPE(sym.st_info));
481a85fe12eSEd Maste 			/* XXX We should globalize weak symbol? */
482a85fe12eSEd Maste 		}
483a85fe12eSEd Maste 
484a85fe12eSEd Maste 		/* Check if we need to rename this symbol. */
485a85fe12eSEd Maste 		if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
486a85fe12eSEd Maste 			name = sp->newname;
487a85fe12eSEd Maste 
488a85fe12eSEd Maste 		/* Check if we need to prefix the symbols. */
489a85fe12eSEd Maste 		newname = NULL;
490a85fe12eSEd Maste 		if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') {
491a85fe12eSEd Maste 			namelen = strlen(name) + strlen(ecp->prefix_sym) + 1;
492a85fe12eSEd Maste 			if ((newname = malloc(namelen)) == NULL)
493a85fe12eSEd Maste 				err(EXIT_FAILURE, "malloc failed");
494a85fe12eSEd Maste 			snprintf(newname, namelen, "%s%s", ecp->prefix_sym,
495a85fe12eSEd Maste 			    name);
496a85fe12eSEd Maste 			name = newname;
497a85fe12eSEd Maste 		}
498a85fe12eSEd Maste 
499a85fe12eSEd Maste 		/* Copy symbol, mark global/weak symbol and add to index map. */
500a85fe12eSEd Maste 		if (is_global_symbol(sym.st_info) ||
501a85fe12eSEd Maste 		    is_weak_symbol(sym.st_info)) {
502a85fe12eSEd Maste 			BIT_SET(gsym, i);
503a85fe12eSEd Maste 			ecp->symndx[i] = sy_buf->ngs;
504a85fe12eSEd Maste 		} else
505a85fe12eSEd Maste 			ecp->symndx[i] = sy_buf->nls;
506a85fe12eSEd Maste 		add_to_symtab(ecp, name, sym.st_value, sym.st_size,
507a85fe12eSEd Maste 		    sym.st_shndx, sym.st_info, sym.st_other, 0);
508a85fe12eSEd Maste 
509a85fe12eSEd Maste 		if (newname != NULL)
510a85fe12eSEd Maste 			free(newname);
511a85fe12eSEd Maste 
512a85fe12eSEd Maste 		/*
513a85fe12eSEd Maste 		 * If the symbol is a STT_SECTION symbol, mark the section
514a85fe12eSEd Maste 		 * it points to.
515a85fe12eSEd Maste 		 */
516a85fe12eSEd Maste 		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION)
517a85fe12eSEd Maste 			BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]);
518a85fe12eSEd Maste 	}
519a85fe12eSEd Maste 
520a85fe12eSEd Maste 	/*
521a85fe12eSEd Maste 	 * Give up if there is no real symbols inside the table.
522a85fe12eSEd Maste 	 * XXX The logic here needs to be improved. We need to
523a85fe12eSEd Maste 	 * check if that only local symbol is the reserved symbol.
524a85fe12eSEd Maste 	 */
525a85fe12eSEd Maste 	if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
526a85fe12eSEd Maste 		return (0);
527a85fe12eSEd Maste 
528a85fe12eSEd Maste 	/*
529a85fe12eSEd Maste 	 * Create STT_SECTION symbols for sections that do not already
530a85fe12eSEd Maste 	 * got one. However, we do not create STT_SECTION symbol for
531a85fe12eSEd Maste 	 * .symtab, .strtab, .shstrtab and reloc sec of relocatables.
532a85fe12eSEd Maste 	 */
533a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
534a85fe12eSEd Maste 		if (s->pseudo)
535a85fe12eSEd Maste 			continue;
536a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
537a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
538a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
539a85fe12eSEd Maste 			continue;
540a85fe12eSEd Maste 		if ((ecp->flags & RELOCATABLE) != 0 &&
541a85fe12eSEd Maste 		    ((s->type == SHT_REL) || (s->type == SHT_RELA)))
542a85fe12eSEd Maste 			continue;
543a85fe12eSEd Maste 
544a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
545a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
546a85fe12eSEd Maste 			    elf_errmsg(-1));
547a85fe12eSEd Maste 
548a85fe12eSEd Maste 		if (!BIT_ISSET(ecp->v_secsym, ndx)) {
549a85fe12eSEd Maste 			sym.st_name  = 0;
550a85fe12eSEd Maste 			sym.st_value = s->vma;
551a85fe12eSEd Maste 			sym.st_size  = 0;
552a85fe12eSEd Maste 			sym.st_info  = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
553a85fe12eSEd Maste 			/*
554a85fe12eSEd Maste 			 * Don't let add_to_symtab() touch sym.st_shndx.
555a85fe12eSEd Maste 			 * In this case, we know the index already.
556a85fe12eSEd Maste 			 */
557a85fe12eSEd Maste 			add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
558a85fe12eSEd Maste 			    ndx, sym.st_info, sym.st_other, 1);
559a85fe12eSEd Maste 		}
560a85fe12eSEd Maste 	}
561a85fe12eSEd Maste 
562a85fe12eSEd Maste 	/*
563a85fe12eSEd Maste 	 * Update st_name and index map for global/weak symbols. Note that
564a85fe12eSEd Maste 	 * global/weak symbols are put after local symbols.
565a85fe12eSEd Maste 	 */
566a85fe12eSEd Maste 	if (gsym != NULL) {
567a85fe12eSEd Maste 		for(i = 0; (size_t) i < sc; i++) {
568a85fe12eSEd Maste 			if (!BIT_ISSET(gsym, i))
569a85fe12eSEd Maste 				continue;
570a85fe12eSEd Maste 
571a85fe12eSEd Maste 			/* Update st_name. */
572a85fe12eSEd Maste 			if (ec == ELFCLASS32)
573a85fe12eSEd Maste 				sy_buf->g32[ecp->symndx[i]].st_name +=
5744a85c691SEd Maste 				    st_buf->l.sz;
575a85fe12eSEd Maste 			else
576a85fe12eSEd Maste 				sy_buf->g64[ecp->symndx[i]].st_name +=
5774a85c691SEd Maste 				    st_buf->l.sz;
578a85fe12eSEd Maste 
579a85fe12eSEd Maste 			/* Update index map. */
580a85fe12eSEd Maste 			ecp->symndx[i] += sy_buf->nls;
581a85fe12eSEd Maste 		}
582a85fe12eSEd Maste 		free(gsym);
583a85fe12eSEd Maste 	}
584a85fe12eSEd Maste 
585a85fe12eSEd Maste 	return (1);
586a85fe12eSEd Maste }
587a85fe12eSEd Maste 
588a85fe12eSEd Maste void
589a85fe12eSEd Maste create_symtab(struct elfcopy *ecp)
590a85fe12eSEd Maste {
591a85fe12eSEd Maste 	struct section	*s, *sy, *st;
592a85fe12eSEd Maste 	size_t		 maxndx, ndx;
593a85fe12eSEd Maste 
594a85fe12eSEd Maste 	sy = ecp->symtab;
595a85fe12eSEd Maste 	st = ecp->strtab;
596a85fe12eSEd Maste 
597a85fe12eSEd Maste 	/*
598a85fe12eSEd Maste 	 * Set section index map for .symtab and .strtab. We need to set
599a85fe12eSEd Maste 	 * these map because otherwise symbols which refer to .symtab and
600a85fe12eSEd Maste 	 * .strtab will be removed by symbol filtering unconditionally.
601a85fe12eSEd Maste 	 * And we have to figure out scn index this way (instead of calling
602a85fe12eSEd Maste 	 * elf_ndxscn) because we can not create Elf_Scn before we're certain
603a85fe12eSEd Maste 	 * that .symtab and .strtab will exist in the output object.
604a85fe12eSEd Maste 	 */
605a85fe12eSEd Maste 	maxndx = 0;
606a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
607a85fe12eSEd Maste 		if (s->os == NULL)
608a85fe12eSEd Maste 			continue;
609a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
610a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
611a85fe12eSEd Maste 			    elf_errmsg(-1));
612a85fe12eSEd Maste 		if (ndx > maxndx)
613a85fe12eSEd Maste 			maxndx = ndx;
614a85fe12eSEd Maste 	}
615a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
616a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
617a85fe12eSEd Maste 
618a85fe12eSEd Maste 	/*
619a85fe12eSEd Maste 	 * Generate symbols for output object if SYMTAB_INTACT is not set.
620a85fe12eSEd Maste 	 * If there is no symbol in the input object or all the symbols are
621a85fe12eSEd Maste 	 * stripped, then free all the resouces allotted for symbol table,
622a85fe12eSEd Maste 	 * and clear SYMTAB_EXIST flag.
623a85fe12eSEd Maste 	 */
624a85fe12eSEd Maste 	if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
625a85fe12eSEd Maste 		TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
626a85fe12eSEd Maste 		TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
627a85fe12eSEd Maste 		free(ecp->symtab);
628a85fe12eSEd Maste 		free(ecp->strtab);
629a85fe12eSEd Maste 		ecp->symtab = NULL;
630a85fe12eSEd Maste 		ecp->strtab = NULL;
631a85fe12eSEd Maste 		ecp->flags &= ~SYMTAB_EXIST;
632a85fe12eSEd Maste 		return;
633a85fe12eSEd Maste 	}
634a85fe12eSEd Maste 
635a85fe12eSEd Maste 	/* Create output Elf_Scn for .symtab and .strtab. */
636a85fe12eSEd Maste 	if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
637a85fe12eSEd Maste 	    (st->os = elf_newscn(ecp->eout)) == NULL)
638a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newscn failed: %s",
639a85fe12eSEd Maste 		    elf_errmsg(-1));
640a85fe12eSEd Maste 	/* Update secndx anyway. */
641a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
642a85fe12eSEd Maste 	ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
643a85fe12eSEd Maste 
644a85fe12eSEd Maste 	/*
645a85fe12eSEd Maste 	 * Copy .symtab and .strtab section headers from input to output
646a85fe12eSEd Maste 	 * object to start with, these will be overridden later if need.
647a85fe12eSEd Maste 	 */
648a85fe12eSEd Maste 	copy_shdr(ecp, sy, ".symtab", 1, 0);
649a85fe12eSEd Maste 	copy_shdr(ecp, st, ".strtab", 1, 0);
650a85fe12eSEd Maste 
651a85fe12eSEd Maste 	/* Copy verbatim if symbol table is intact. */
652a85fe12eSEd Maste 	if (ecp->flags & SYMTAB_INTACT) {
653a85fe12eSEd Maste 		copy_data(sy);
654a85fe12eSEd Maste 		copy_data(st);
655a85fe12eSEd Maste 		return;
656a85fe12eSEd Maste 	}
657a85fe12eSEd Maste 
658a85fe12eSEd Maste 	create_symtab_data(ecp);
659a85fe12eSEd Maste }
660a85fe12eSEd Maste 
661a85fe12eSEd Maste void
662a85fe12eSEd Maste free_symtab(struct elfcopy *ecp)
663a85fe12eSEd Maste {
664a85fe12eSEd Maste 	struct symbuf	*sy_buf;
665a85fe12eSEd Maste 	struct strbuf	*st_buf;
6664a85c691SEd Maste 	struct sthash	*sh, *shtmp;
6674a85c691SEd Maste 	int i;
668a85fe12eSEd Maste 
669a85fe12eSEd Maste 	if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
670a85fe12eSEd Maste 		sy_buf = ecp->symtab->buf;
671a85fe12eSEd Maste 		if (sy_buf->l32 != NULL)
672a85fe12eSEd Maste 			free(sy_buf->l32);
673a85fe12eSEd Maste 		if (sy_buf->g32 != NULL)
674a85fe12eSEd Maste 			free(sy_buf->g32);
675a85fe12eSEd Maste 		if (sy_buf->l64 != NULL)
676a85fe12eSEd Maste 			free(sy_buf->l64);
677a85fe12eSEd Maste 		if (sy_buf->g64 != NULL)
678a85fe12eSEd Maste 			free(sy_buf->g64);
679a85fe12eSEd Maste 	}
680a85fe12eSEd Maste 
681a85fe12eSEd Maste 	if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
682a85fe12eSEd Maste 		st_buf = ecp->strtab->buf;
6834a85c691SEd Maste 		if (st_buf->l.buf != NULL)
6844a85c691SEd Maste 			free(st_buf->l.buf);
6854a85c691SEd Maste 		if (st_buf->g.buf != NULL)
6864a85c691SEd Maste 			free(st_buf->g.buf);
6874a85c691SEd Maste 		for (i = 0; i < STHASHSIZE; i++) {
6884a85c691SEd Maste 			LIST_FOREACH_SAFE(sh, &st_buf->l.hash[i], sh_next,
6894a85c691SEd Maste 			    shtmp) {
6904a85c691SEd Maste 				LIST_REMOVE(sh, sh_next);
6914a85c691SEd Maste 				free(sh);
6924a85c691SEd Maste 			}
6934a85c691SEd Maste 			LIST_FOREACH_SAFE(sh, &st_buf->g.hash[i], sh_next,
6944a85c691SEd Maste 			    shtmp) {
6954a85c691SEd Maste 				LIST_REMOVE(sh, sh_next);
6964a85c691SEd Maste 				free(sh);
6974a85c691SEd Maste 			}
6984a85c691SEd Maste 		}
699a85fe12eSEd Maste 	}
700a85fe12eSEd Maste }
701a85fe12eSEd Maste 
702a85fe12eSEd Maste void
703a85fe12eSEd Maste create_external_symtab(struct elfcopy *ecp)
704a85fe12eSEd Maste {
705a85fe12eSEd Maste 	struct section *s;
706a85fe12eSEd Maste 	struct symbuf *sy_buf;
707a85fe12eSEd Maste 	struct strbuf *st_buf;
708a85fe12eSEd Maste 	GElf_Shdr sh;
709a85fe12eSEd Maste 	size_t ndx;
710a85fe12eSEd Maste 
711a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32)
712a85fe12eSEd Maste 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
713a85fe12eSEd Maste 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
714a85fe12eSEd Maste 	else
715a85fe12eSEd Maste 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
716a85fe12eSEd Maste 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
717a85fe12eSEd Maste 
718a85fe12eSEd Maste 	ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
719a85fe12eSEd Maste 	    SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
720a85fe12eSEd Maste 
721a85fe12eSEd Maste 	/* Let sh_link field of .symtab section point to .strtab section. */
722a85fe12eSEd Maste 	if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
723a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
724a85fe12eSEd Maste 		    elf_errmsg(-1));
725a85fe12eSEd Maste 	sh.sh_link = elf_ndxscn(ecp->strtab->os);
726a85fe12eSEd Maste 	if (!gelf_update_shdr(ecp->symtab->os, &sh))
727a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
728a85fe12eSEd Maste 		    elf_errmsg(-1));
729a85fe12eSEd Maste 
730a85fe12eSEd Maste 	/* Create buffers for .symtab and .strtab. */
731a85fe12eSEd Maste 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
732a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
733a85fe12eSEd Maste 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
734a85fe12eSEd Maste 		err(EXIT_FAILURE, "calloc failed");
735a85fe12eSEd Maste 	sy_buf->gcap = sy_buf->lcap = 64;
7364a85c691SEd Maste 	st_buf->g.cap = 256;
7374a85c691SEd Maste 	st_buf->l.cap = 64;
7384a85c691SEd Maste 	st_buf->l.sz = 1;	/* '\0' at start. */
7394a85c691SEd Maste 	st_buf->g.sz = 0;
740a85fe12eSEd Maste 
741a85fe12eSEd Maste 	ecp->symtab->sz = 0;
742a85fe12eSEd Maste 	ecp->strtab->sz = 0;
743a85fe12eSEd Maste 	ecp->symtab->buf = sy_buf;
744a85fe12eSEd Maste 	ecp->strtab->buf = st_buf;
745a85fe12eSEd Maste 
746a85fe12eSEd Maste 	/* Always create the special symbol at the symtab beginning. */
747a85fe12eSEd Maste 	add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
748a85fe12eSEd Maste 	    ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
749a85fe12eSEd Maste 
750a85fe12eSEd Maste 	/* Create STT_SECTION symbols. */
751a85fe12eSEd Maste 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
752a85fe12eSEd Maste 		if (s->pseudo)
753a85fe12eSEd Maste 			continue;
754a85fe12eSEd Maste 		if (strcmp(s->name, ".symtab") == 0 ||
755a85fe12eSEd Maste 		    strcmp(s->name, ".strtab") == 0 ||
756a85fe12eSEd Maste 		    strcmp(s->name, ".shstrtab") == 0)
757a85fe12eSEd Maste 			continue;
758a85fe12eSEd Maste 		(void) elf_errno();
759a85fe12eSEd Maste 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
760a85fe12eSEd Maste 			warnx("elf_ndxscn failed: %s",
761a85fe12eSEd Maste 			    elf_errmsg(-1));
762a85fe12eSEd Maste 			continue;
763a85fe12eSEd Maste 		}
764a85fe12eSEd Maste 		add_to_symtab(ecp, NULL, 0, 0, ndx,
765a85fe12eSEd Maste 		    GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
766a85fe12eSEd Maste 	}
767a85fe12eSEd Maste }
768a85fe12eSEd Maste 
769a85fe12eSEd Maste void
770a85fe12eSEd Maste add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
771a85fe12eSEd Maste     uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
772a85fe12eSEd Maste     unsigned char st_other, int ndx_known)
773a85fe12eSEd Maste {
774a85fe12eSEd Maste 	struct symbuf *sy_buf;
775a85fe12eSEd Maste 	struct strbuf *st_buf;
7764a85c691SEd Maste 	struct sthash *sh;
7774a85c691SEd Maste 	uint32_t hash;
778a85fe12eSEd Maste 	int pos;
779a85fe12eSEd Maste 
780a85fe12eSEd Maste 	/*
781a85fe12eSEd Maste 	 * Convenient macro for copying global/local 32/64 bit symbols
782a85fe12eSEd Maste 	 * from input object to the buffer created for output object.
783a85fe12eSEd Maste 	 * It handles buffer growing, st_name calculating and st_shndx
784a85fe12eSEd Maste 	 * updating for symbols with non-special section index.
785a85fe12eSEd Maste 	 */
786a85fe12eSEd Maste #define	_ADDSYM(B, SZ) do {						\
787a85fe12eSEd Maste 	if (sy_buf->B##SZ == NULL) {					\
788a85fe12eSEd Maste 		sy_buf->B##SZ = malloc(sy_buf->B##cap *			\
789a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Sym));				\
790a85fe12eSEd Maste 		if (sy_buf->B##SZ == NULL)				\
791a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");		\
792a85fe12eSEd Maste 	} else if (sy_buf->n##B##s >= sy_buf->B##cap) {			\
793a85fe12eSEd Maste 		sy_buf->B##cap *= 2;					\
794a85fe12eSEd Maste 		sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap *	\
795a85fe12eSEd Maste 		    sizeof(Elf##SZ##_Sym));				\
796a85fe12eSEd Maste 		if (sy_buf->B##SZ == NULL)				\
797a85fe12eSEd Maste 			err(EXIT_FAILURE, "realloc failed");		\
798a85fe12eSEd Maste 	}								\
799a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_info	= st_info;		\
800a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_other	= st_other;		\
801a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_value	= st_value;		\
802a85fe12eSEd Maste 	sy_buf->B##SZ[sy_buf->n##B##s].st_size	= st_size;		\
803a85fe12eSEd Maste 	if (ndx_known)							\
804a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
805a85fe12eSEd Maste 	else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE)	\
806a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
807a85fe12eSEd Maste 	else								\
808a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx	=		\
809a85fe12eSEd Maste 			ecp->secndx[st_shndx];				\
8104a85c691SEd Maste 	if (st_buf->B.buf == NULL) {					\
8114a85c691SEd Maste 		st_buf->B.buf = calloc(st_buf->B.cap,			\
8124a85c691SEd Maste 		    sizeof(*st_buf->B.buf));				\
8134a85c691SEd Maste 		if (st_buf->B.buf == NULL)				\
814a85fe12eSEd Maste 			err(EXIT_FAILURE, "malloc failed");		\
815a85fe12eSEd Maste 	}								\
816a85fe12eSEd Maste 	if (name != NULL && *name != '\0') {				\
8174a85c691SEd Maste 		pos = lookup_exact_string(st_buf->B.hash, st_buf->B.buf,\
8184a85c691SEd Maste 		    name);						\
819a85fe12eSEd Maste 		if (pos != -1)						\
820a85fe12eSEd Maste 			sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos;	\
821a85fe12eSEd Maste 		else {							\
822a85fe12eSEd Maste 			sy_buf->B##SZ[sy_buf->n##B##s].st_name =	\
8234a85c691SEd Maste 			    st_buf->B.sz;				\
8244a85c691SEd Maste 			while (st_buf->B.sz + strlen(name) >=		\
8254a85c691SEd Maste 			    st_buf->B.cap - 1) {			\
8264a85c691SEd Maste 				st_buf->B.cap *= 2;			\
8274a85c691SEd Maste 				st_buf->B.buf = realloc(st_buf->B.buf,	\
8284a85c691SEd Maste 				    st_buf->B.cap);			\
8294a85c691SEd Maste 				if (st_buf->B.buf == NULL)		\
830a85fe12eSEd Maste 					err(EXIT_FAILURE,		\
831a85fe12eSEd Maste 					    "realloc failed");		\
832a85fe12eSEd Maste 			}						\
8334a85c691SEd Maste 			if ((sh = malloc(sizeof(*sh))) == NULL)		\
8344a85c691SEd Maste 				err(EXIT_FAILURE, "malloc failed");	\
8354a85c691SEd Maste 			sh->sh_off = st_buf->B.sz;			\
8364a85c691SEd Maste 			hash = str_hash(name);				\
8374a85c691SEd Maste 			LIST_INSERT_HEAD(&st_buf->B.hash[hash], sh,	\
8384a85c691SEd Maste 			    sh_next);					\
8394a85c691SEd Maste 			strncpy(&st_buf->B.buf[st_buf->B.sz], name,	\
840a85fe12eSEd Maste 			    strlen(name));				\
8414a85c691SEd Maste 			st_buf->B.buf[st_buf->B.sz + strlen(name)] = '\0'; \
8424a85c691SEd Maste 			st_buf->B.sz += strlen(name) + 1;		\
843a85fe12eSEd Maste 		}							\
844a85fe12eSEd Maste 	} else								\
845a85fe12eSEd Maste 		sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0;		\
846a85fe12eSEd Maste 	sy_buf->n##B##s++;						\
847a85fe12eSEd Maste } while (0)
848a85fe12eSEd Maste 
849a85fe12eSEd Maste 	sy_buf = ecp->symtab->buf;
850a85fe12eSEd Maste 	st_buf = ecp->strtab->buf;
851a85fe12eSEd Maste 
852a85fe12eSEd Maste 	if (ecp->oec == ELFCLASS32) {
853a85fe12eSEd Maste 		if (is_local_symbol(st_info))
854a85fe12eSEd Maste 			_ADDSYM(l, 32);
855a85fe12eSEd Maste 		else
856a85fe12eSEd Maste 			_ADDSYM(g, 32);
857a85fe12eSEd Maste 	} else {
858a85fe12eSEd Maste 		if (is_local_symbol(st_info))
859a85fe12eSEd Maste 			_ADDSYM(l, 64);
860a85fe12eSEd Maste 		else
861a85fe12eSEd Maste 			_ADDSYM(g, 64);
862a85fe12eSEd Maste 	}
863a85fe12eSEd Maste 
864a85fe12eSEd Maste 	/* Update section size. */
865a85fe12eSEd Maste 	ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
866a85fe12eSEd Maste 	    (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
8674a85c691SEd Maste 	ecp->strtab->sz = st_buf->l.sz + st_buf->g.sz;
868a85fe12eSEd Maste 
869a85fe12eSEd Maste #undef	_ADDSYM
870a85fe12eSEd Maste }
871a85fe12eSEd Maste 
872a85fe12eSEd Maste void
873a85fe12eSEd Maste finalize_external_symtab(struct elfcopy *ecp)
874a85fe12eSEd Maste {
875a85fe12eSEd Maste 	struct symbuf *sy_buf;
876a85fe12eSEd Maste 	struct strbuf *st_buf;
877a85fe12eSEd Maste 	int i;
878a85fe12eSEd Maste 
879a85fe12eSEd Maste 	/*
880a85fe12eSEd Maste 	 * Update st_name for global/weak symbols. (global/weak symbols
881a85fe12eSEd Maste 	 * are put after local symbols)
882a85fe12eSEd Maste 	 */
883a85fe12eSEd Maste 	sy_buf = ecp->symtab->buf;
884a85fe12eSEd Maste 	st_buf = ecp->strtab->buf;
885a85fe12eSEd Maste 	for (i = 0; (size_t) i < sy_buf->ngs; i++) {
886a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32)
8874a85c691SEd Maste 			sy_buf->g32[i].st_name += st_buf->l.sz;
888a85fe12eSEd Maste 		else
8894a85c691SEd Maste 			sy_buf->g64[i].st_name += st_buf->l.sz;
890a85fe12eSEd Maste 	}
891a85fe12eSEd Maste }
892a85fe12eSEd Maste 
893a85fe12eSEd Maste void
894a85fe12eSEd Maste create_symtab_data(struct elfcopy *ecp)
895a85fe12eSEd Maste {
896a85fe12eSEd Maste 	struct section	*sy, *st;
897a85fe12eSEd Maste 	struct symbuf	*sy_buf;
898a85fe12eSEd Maste 	struct strbuf	*st_buf;
899a85fe12eSEd Maste 	Elf_Data	*gsydata, *lsydata, *gstdata, *lstdata;
900a85fe12eSEd Maste 	GElf_Shdr	 shy, sht;
901a85fe12eSEd Maste 
902a85fe12eSEd Maste 	sy = ecp->symtab;
903a85fe12eSEd Maste 	st = ecp->strtab;
904a85fe12eSEd Maste 
905a85fe12eSEd Maste 	if (gelf_getshdr(sy->os, &shy) == NULL)
906a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
907a85fe12eSEd Maste 		    elf_errmsg(-1));
908a85fe12eSEd Maste 	if (gelf_getshdr(st->os, &sht) == NULL)
909a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
910a85fe12eSEd Maste 		    elf_errmsg(-1));
911a85fe12eSEd Maste 
912a85fe12eSEd Maste 	/*
913a85fe12eSEd Maste 	 * Create two Elf_Data for .symtab section of output object, one
914a85fe12eSEd Maste 	 * for local symbols and another for global symbols. Note that
915a85fe12eSEd Maste 	 * local symbols appear first in the .symtab.
916a85fe12eSEd Maste 	 */
917a85fe12eSEd Maste 	sy_buf = sy->buf;
918a85fe12eSEd Maste 	if (sy_buf->nls > 0) {
919a85fe12eSEd Maste 		if ((lsydata = elf_newdata(sy->os)) == NULL)
920a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
921a85fe12eSEd Maste 			     elf_errmsg(-1));
922a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32) {
923a85fe12eSEd Maste 			lsydata->d_align	= 4;
924a85fe12eSEd Maste 			lsydata->d_off		= 0;
925a85fe12eSEd Maste 			lsydata->d_buf		= sy_buf->l32;
926a85fe12eSEd Maste 			lsydata->d_size		= sy_buf->nls *
927a85fe12eSEd Maste 				sizeof(Elf32_Sym);
928a85fe12eSEd Maste 			lsydata->d_type		= ELF_T_SYM;
929a85fe12eSEd Maste 			lsydata->d_version	= EV_CURRENT;
930a85fe12eSEd Maste 		} else {
931a85fe12eSEd Maste 			lsydata->d_align	= 8;
932a85fe12eSEd Maste 			lsydata->d_off		= 0;
933a85fe12eSEd Maste 			lsydata->d_buf		= sy_buf->l64;
934a85fe12eSEd Maste 			lsydata->d_size		= sy_buf->nls *
935a85fe12eSEd Maste 				sizeof(Elf64_Sym);
936a85fe12eSEd Maste 			lsydata->d_type		= ELF_T_SYM;
937a85fe12eSEd Maste 			lsydata->d_version	= EV_CURRENT;
938a85fe12eSEd Maste 		}
939a85fe12eSEd Maste 	}
940a85fe12eSEd Maste 	if (sy_buf->ngs > 0) {
941a85fe12eSEd Maste 		if ((gsydata = elf_newdata(sy->os)) == NULL)
942a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
943a85fe12eSEd Maste 			     elf_errmsg(-1));
944a85fe12eSEd Maste 		if (ecp->oec == ELFCLASS32) {
945a85fe12eSEd Maste 			gsydata->d_align	= 4;
946a85fe12eSEd Maste 			gsydata->d_off		= sy_buf->nls *
947a85fe12eSEd Maste 				sizeof(Elf32_Sym);
948a85fe12eSEd Maste 			gsydata->d_buf		= sy_buf->g32;
949a85fe12eSEd Maste 			gsydata->d_size		= sy_buf->ngs *
950a85fe12eSEd Maste 				sizeof(Elf32_Sym);
951a85fe12eSEd Maste 			gsydata->d_type		= ELF_T_SYM;
952a85fe12eSEd Maste 			gsydata->d_version	= EV_CURRENT;
953a85fe12eSEd Maste 		} else {
954a85fe12eSEd Maste 			gsydata->d_align	= 8;
955a85fe12eSEd Maste 			gsydata->d_off		= sy_buf->nls *
956a85fe12eSEd Maste 				sizeof(Elf64_Sym);
957a85fe12eSEd Maste 			gsydata->d_buf		= sy_buf->g64;
958a85fe12eSEd Maste 			gsydata->d_size		= sy_buf->ngs *
959a85fe12eSEd Maste 				sizeof(Elf64_Sym);
960a85fe12eSEd Maste 			gsydata->d_type		= ELF_T_SYM;
961a85fe12eSEd Maste 			gsydata->d_version	= EV_CURRENT;
962a85fe12eSEd Maste 		}
963a85fe12eSEd Maste 	}
964a85fe12eSEd Maste 
965a85fe12eSEd Maste 	/*
966a85fe12eSEd Maste 	 * Create two Elf_Data for .strtab, one for local symbol name
967a85fe12eSEd Maste 	 * and another for globals. Same as .symtab, local symbol names
968a85fe12eSEd Maste 	 * appear first.
969a85fe12eSEd Maste 	 */
970a85fe12eSEd Maste 	st_buf = st->buf;
971a85fe12eSEd Maste 	if ((lstdata = elf_newdata(st->os)) == NULL)
972a85fe12eSEd Maste 		errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
973a85fe12eSEd Maste 		    elf_errmsg(-1));
974a85fe12eSEd Maste 	lstdata->d_align	= 1;
975a85fe12eSEd Maste 	lstdata->d_off		= 0;
9764a85c691SEd Maste 	lstdata->d_buf		= st_buf->l.buf;
9774a85c691SEd Maste 	lstdata->d_size		= st_buf->l.sz;
978a85fe12eSEd Maste 	lstdata->d_type		= ELF_T_BYTE;
979a85fe12eSEd Maste 	lstdata->d_version	= EV_CURRENT;
980a85fe12eSEd Maste 
9814a85c691SEd Maste 	if (st_buf->g.sz > 0) {
982a85fe12eSEd Maste 		if ((gstdata = elf_newdata(st->os)) == NULL)
983a85fe12eSEd Maste 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
984a85fe12eSEd Maste 			    elf_errmsg(-1));
985a85fe12eSEd Maste 		gstdata->d_align	= 1;
986a85fe12eSEd Maste 		gstdata->d_off		= lstdata->d_size;
9874a85c691SEd Maste 		gstdata->d_buf		= st_buf->g.buf;
9884a85c691SEd Maste 		gstdata->d_size		= st_buf->g.sz;
989a85fe12eSEd Maste 		gstdata->d_type		= ELF_T_BYTE;
990a85fe12eSEd Maste 		gstdata->d_version	= EV_CURRENT;
991a85fe12eSEd Maste 	}
992a85fe12eSEd Maste 
993a85fe12eSEd Maste 	shy.sh_addr		= 0;
994a85fe12eSEd Maste 	shy.sh_addralign	= (ecp->oec == ELFCLASS32 ? 4 : 8);
995a85fe12eSEd Maste 	shy.sh_size		= sy->sz;
996a85fe12eSEd Maste 	shy.sh_type		= SHT_SYMTAB;
997a85fe12eSEd Maste 	shy.sh_flags		= 0;
998a85fe12eSEd Maste 	shy.sh_entsize		= gelf_fsize(ecp->eout, ELF_T_SYM, 1,
999a85fe12eSEd Maste 	    EV_CURRENT);
1000a85fe12eSEd Maste 	/*
1001a85fe12eSEd Maste 	 * According to SYSV abi, here sh_info is one greater than
1002a85fe12eSEd Maste 	 * the symbol table index of the last local symbol(binding
1003a85fe12eSEd Maste 	 * STB_LOCAL).
1004a85fe12eSEd Maste 	 */
1005a85fe12eSEd Maste 	shy.sh_info		= sy_buf->nls;
1006a85fe12eSEd Maste 
1007a85fe12eSEd Maste 	sht.sh_addr		= 0;
1008a85fe12eSEd Maste 	sht.sh_addralign	= 1;
1009a85fe12eSEd Maste 	sht.sh_size		= st->sz;
1010a85fe12eSEd Maste 	sht.sh_type		= SHT_STRTAB;
1011a85fe12eSEd Maste 	sht.sh_flags		= 0;
1012a85fe12eSEd Maste 	sht.sh_entsize		= 0;
1013a85fe12eSEd Maste 	sht.sh_info		= 0;
1014a85fe12eSEd Maste 	sht.sh_link		= 0;
1015a85fe12eSEd Maste 
1016a85fe12eSEd Maste 	if (!gelf_update_shdr(sy->os, &shy))
1017a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1018a85fe12eSEd Maste 		    elf_errmsg(-1));
1019a85fe12eSEd Maste 	if (!gelf_update_shdr(st->os, &sht))
1020a85fe12eSEd Maste 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
1021a85fe12eSEd Maste 		    elf_errmsg(-1));
1022a85fe12eSEd Maste }
1023a85fe12eSEd Maste 
1024a85fe12eSEd Maste void
1025a85fe12eSEd Maste add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
1026a85fe12eSEd Maste     unsigned int op)
1027a85fe12eSEd Maste {
1028a85fe12eSEd Maste 	struct symop *s;
1029a85fe12eSEd Maste 
1030a85fe12eSEd Maste 	if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) {
1031a85fe12eSEd Maste 		if ((s = calloc(1, sizeof(*s))) == NULL)
1032a85fe12eSEd Maste 			errx(EXIT_FAILURE, "not enough memory");
1033a85fe12eSEd Maste 		s->name = name;
1034a85fe12eSEd Maste 		if (op == SYMOP_REDEF)
1035a85fe12eSEd Maste 			s->newname = newname;
1036a85fe12eSEd Maste 	}
1037a85fe12eSEd Maste 
1038a85fe12eSEd Maste 	s->op |= op;
1039a85fe12eSEd Maste 	STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
1040a85fe12eSEd Maste }
1041a85fe12eSEd Maste 
1042a85fe12eSEd Maste static int
1043a85fe12eSEd Maste match_wildcard(const char *name, const char *pattern)
1044a85fe12eSEd Maste {
1045a85fe12eSEd Maste 	int reverse, match;
1046a85fe12eSEd Maste 
1047a85fe12eSEd Maste 	reverse = 0;
1048a85fe12eSEd Maste 	if (*pattern == '!') {
1049a85fe12eSEd Maste 		reverse = 1;
1050a85fe12eSEd Maste 		pattern++;
1051a85fe12eSEd Maste 	}
1052a85fe12eSEd Maste 
1053a85fe12eSEd Maste 	match = 0;
105467d97fe7SEd Maste 	if (!fnmatch(pattern, name, 0))
1055a85fe12eSEd Maste 		match = 1;
1056a85fe12eSEd Maste 
1057a85fe12eSEd Maste 	return (reverse ? !match : match);
1058a85fe12eSEd Maste }
1059a85fe12eSEd Maste 
1060a85fe12eSEd Maste struct symop *
1061a85fe12eSEd Maste lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1062a85fe12eSEd Maste {
1063a85fe12eSEd Maste 	struct symop *s;
1064a85fe12eSEd Maste 
1065a85fe12eSEd Maste 	STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1066a85fe12eSEd Maste 		if (name == NULL || !strcmp(name, s->name) ||
1067a85fe12eSEd Maste 		    ((ecp->flags & WILDCARD) && match_wildcard(name, s->name)))
1068a85fe12eSEd Maste 			if ((s->op & op) != 0)
1069a85fe12eSEd Maste 				return (s);
1070a85fe12eSEd Maste 	}
1071a85fe12eSEd Maste 
1072a85fe12eSEd Maste 	return (NULL);
1073a85fe12eSEd Maste }
1074a85fe12eSEd Maste 
1075a85fe12eSEd Maste static int
10764a85c691SEd Maste lookup_exact_string(hash_head *buckets, const char *buf, const char *s)
1077a85fe12eSEd Maste {
10784a85c691SEd Maste 	struct sthash	*sh;
10794a85c691SEd Maste 	uint32_t	 hash;
1080a85fe12eSEd Maste 
10814a85c691SEd Maste 	hash = str_hash(s);
10824a85c691SEd Maste 	LIST_FOREACH(sh, &buckets[hash], sh_next)
10834a85c691SEd Maste 		if (strcmp(buf + sh->sh_off, s) == 0)
10844a85c691SEd Maste 			return sh->sh_off;
10854a85c691SEd Maste 	return (-1);
1086a85fe12eSEd Maste }
1087a85fe12eSEd Maste 
10884a85c691SEd Maste uint32_t
10894a85c691SEd Maste str_hash(const char *s)
10904a85c691SEd Maste {
10914a85c691SEd Maste 	uint32_t hash;
10924a85c691SEd Maste 
1093*b00fe64fSEd Maste 	for (hash = 2166136261UL; *s; s++)
10944a85c691SEd Maste 		hash = (hash ^ *s) * 16777619;
10954a85c691SEd Maste 
10964a85c691SEd Maste 	return (hash & (STHASHSIZE - 1));
1097a85fe12eSEd Maste }
1098