xref: /freebsd/contrib/elftoolchain/elfcopy/symbols.c (revision bbb29a3c0f2c4565eff6fda70426807b6ed97f8b)
1 /*-
2  * Copyright (c) 2007-2013 Kai Wang
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 #include <sys/param.h>
29 #include <err.h>
30 #include <fnmatch.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 
35 #include "elfcopy.h"
36 
37 ELFTC_VCSID("$Id: symbols.c 2971 2013-12-01 15:22:21Z kaiwang27 $");
38 
39 /* Symbol table buffer structure. */
40 struct symbuf {
41 	Elf32_Sym *l32;		/* 32bit local symbol */
42 	Elf32_Sym *g32;		/* 32bit global symbol */
43 	Elf64_Sym *l64;		/* 64bit local symbol */
44 	Elf64_Sym *g64;		/* 64bit global symbol */
45 	size_t ngs, nls;	/* number of each kind */
46 	size_t gcap, lcap; 	/* buffer capacities. */
47 };
48 
49 /* String table buffer structure. */
50 struct strbuf {
51 	char *l;		/* local symbol string table */
52 	char *g;		/* global symbol string table */
53 	size_t lsz, gsz;	/* size of each kind */
54 	size_t gcap, lcap; 	/* buffer capacities. */
55 };
56 
57 static int	is_debug_symbol(unsigned char st_info);
58 static int	is_global_symbol(unsigned char st_info);
59 static int	is_local_symbol(unsigned char st_info);
60 static int	is_local_label(const char *name);
61 static int	is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s);
62 static int	is_remove_symbol(struct elfcopy *ecp, size_t sc, int i,
63 		    GElf_Sym *s, const char *name);
64 static int	is_weak_symbol(unsigned char st_info);
65 static int	lookup_exact_string(const char *buf, size_t sz, const char *s);
66 static int	generate_symbols(struct elfcopy *ecp);
67 static void	mark_symbols(struct elfcopy *ecp, size_t sc);
68 static int	match_wildcard(const char *name, const char *pattern);
69 
70 /* Convenient bit vector operation macros. */
71 #define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))
72 #define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))
73 #define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))
74 
75 static int
76 is_debug_symbol(unsigned char st_info)
77 {
78 
79 	if (GELF_ST_TYPE(st_info) == STT_SECTION ||
80 	    GELF_ST_TYPE(st_info) == STT_FILE)
81 		return (1);
82 
83 	return (0);
84 }
85 
86 static int
87 is_global_symbol(unsigned char st_info)
88 {
89 
90 	if (GELF_ST_BIND(st_info) == STB_GLOBAL)
91 		return (1);
92 
93 	return (0);
94 }
95 
96 static int
97 is_weak_symbol(unsigned char st_info)
98 {
99 
100 	if (GELF_ST_BIND(st_info) == STB_WEAK)
101 		return (1);
102 
103 	return (0);
104 }
105 
106 static int
107 is_local_symbol(unsigned char st_info)
108 {
109 
110 	if (GELF_ST_BIND(st_info) == STB_LOCAL)
111 		return (1);
112 
113 	return (0);
114 }
115 
116 static int
117 is_local_label(const char *name)
118 {
119 
120 	/* Compiler generated local symbols that start with .L */
121 	if (name[0] == '.' && name[1] == 'L')
122 		return (1);
123 
124 	return (0);
125 }
126 
127 /*
128  * Symbols related to relocation are needed.
129  */
130 static int
131 is_needed_symbol(struct elfcopy *ecp, int i, GElf_Sym *s)
132 {
133 
134 	/* If symbol involves relocation, it is needed. */
135 	if (BIT_ISSET(ecp->v_rel, i))
136 		return (1);
137 
138 	/*
139 	 * For relocatable files (.o files), global and weak symbols
140 	 * are needed.
141 	 */
142 	if (ecp->flags & RELOCATABLE) {
143 		if (is_global_symbol(s->st_info) || is_weak_symbol(s->st_info))
144 			return (1);
145 	}
146 
147 	return (0);
148 }
149 
150 static int
151 is_remove_symbol(struct elfcopy *ecp, size_t sc, int i, GElf_Sym *s,
152     const char *name)
153 {
154 	GElf_Sym sym0 = {
155 		0, 		/* st_name */
156 		0,		/* st_value */
157 		0,		/* st_size */
158 		0,		/* st_info */
159 		0,		/* st_other */
160 		SHN_UNDEF,	/* st_shndx */
161 	};
162 
163 	if (lookup_symop_list(ecp, name, SYMOP_KEEP) != NULL)
164 		return (0);
165 
166 	if (lookup_symop_list(ecp, name, SYMOP_STRIP) != NULL)
167 		return (1);
168 
169 	/*
170 	 * Keep the first symbol if it is the special reserved symbol.
171 	 * XXX Should we generate one if it's missing?
172 	 */
173 	if (i == 0 && !memcmp(s, &sym0, sizeof(GElf_Sym)))
174 		return (0);
175 
176 	/* Remove the symbol if the section it refers to was removed. */
177 	if (s->st_shndx != SHN_UNDEF && s->st_shndx < SHN_LORESERVE &&
178 	    ecp->secndx[s->st_shndx] == 0)
179 		return (1);
180 
181 	if (ecp->strip == STRIP_ALL)
182 		return (1);
183 
184 	if (ecp->v_rel == NULL)
185 		mark_symbols(ecp, sc);
186 
187 	if (is_needed_symbol(ecp, i, s))
188 		return (0);
189 
190 	if (ecp->strip == STRIP_UNNEEDED)
191 		return (1);
192 
193 	if ((ecp->flags & DISCARD_LOCAL) && is_local_symbol(s->st_info) &&
194 	    !is_debug_symbol(s->st_info))
195 		return (1);
196 
197 	if ((ecp->flags & DISCARD_LLABEL) && is_local_symbol(s->st_info) &&
198 	    !is_debug_symbol(s->st_info) && is_local_label(name))
199 		return (1);
200 
201 	if (ecp->strip == STRIP_DEBUG && is_debug_symbol(s->st_info))
202 		return (1);
203 
204 	return (0);
205 }
206 
207 /*
208  * Mark symbols refered by relocation entries.
209  */
210 static void
211 mark_symbols(struct elfcopy *ecp, size_t sc)
212 {
213 	const char	*name;
214 	Elf_Data	*d;
215 	Elf_Scn		*s;
216 	GElf_Rel	 r;
217 	GElf_Rela	 ra;
218 	GElf_Shdr	 sh;
219 	size_t		 n, indx;
220 	int		 elferr, i, len;
221 
222 	ecp->v_rel = calloc((sc + 7) / 8, 1);
223 	if (ecp->v_rel == NULL)
224 		err(EXIT_FAILURE, "calloc failed");
225 
226 	if (elf_getshstrndx(ecp->ein, &indx) == 0)
227 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
228 		    elf_errmsg(-1));
229 
230 	s = NULL;
231 	while ((s = elf_nextscn(ecp->ein, s)) != NULL) {
232 		if (gelf_getshdr(s, &sh) != &sh)
233 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
234 			    elf_errmsg(-1));
235 
236 		if (sh.sh_type != SHT_REL && sh.sh_type != SHT_RELA)
237 			continue;
238 
239 		/*
240 		 * Skip if this reloc section won't appear in the
241 		 * output object.
242 		 */
243 		if ((name = elf_strptr(ecp->ein, indx, sh.sh_name)) == NULL)
244 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
245 			    elf_errmsg(-1));
246 		if (is_remove_section(ecp, name) ||
247 		    is_remove_reloc_sec(ecp, sh.sh_info))
248 			continue;
249 
250 		/* Skip if it's not for .symtab */
251 		if (sh.sh_link != elf_ndxscn(ecp->symtab->is))
252 			continue;
253 
254 		d = NULL;
255 		n = 0;
256 		while (n < sh.sh_size && (d = elf_getdata(s, d)) != NULL) {
257 			len = d->d_size / sh.sh_entsize;
258 			for (i = 0; i < len; i++) {
259 				if (sh.sh_type == SHT_REL) {
260 					if (gelf_getrel(d, i, &r) != &r)
261 						errx(EXIT_FAILURE,
262 						    "elf_getrel failed: %s",
263 						     elf_errmsg(-1));
264 					n = GELF_R_SYM(r.r_info);
265 				} else {
266 					if (gelf_getrela(d, i, &ra) != &ra)
267 						errx(EXIT_FAILURE,
268 						    "elf_getrela failed: %s",
269 						     elf_errmsg(-1));
270 					n = GELF_R_SYM(ra.r_info);
271 				}
272 				if (n > 0 && n < sc)
273 					BIT_SET(ecp->v_rel, n);
274 				else if (n != 0)
275 					warnx("invalid symbox index");
276 			}
277 		}
278 		elferr = elf_errno();
279 		if (elferr != 0)
280 			errx(EXIT_FAILURE, "elf_getdata failed: %s",
281 			    elf_errmsg(elferr));
282 	}
283 	elferr = elf_errno();
284 	if (elferr != 0)
285 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
286 		    elf_errmsg(elferr));
287 }
288 
289 static int
290 generate_symbols(struct elfcopy *ecp)
291 {
292 	struct section	*s;
293 	struct symop	*sp;
294 	struct symbuf	*sy_buf;
295 	struct strbuf	*st_buf;
296 	const char	*name;
297 	char		*newname;
298 	unsigned char	*gsym;
299 	GElf_Shdr	 ish;
300 	GElf_Sym	 sym;
301 	Elf_Data*	 id;
302 	Elf_Scn		*is;
303 	size_t		 ishstrndx, namelen, ndx, nsyms, sc, symndx;
304 	int		 ec, elferr, i;
305 
306 	if (elf_getshstrndx(ecp->ein, &ishstrndx) == 0)
307 		errx(EXIT_FAILURE, "elf_getshstrndx failed: %s",
308 		    elf_errmsg(-1));
309 	if ((ec = gelf_getclass(ecp->eout)) == ELFCLASSNONE)
310 		errx(EXIT_FAILURE, "gelf_getclass failed: %s",
311 		    elf_errmsg(-1));
312 
313 	/* Create buffers for .symtab and .strtab. */
314 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
315 		err(EXIT_FAILURE, "calloc failed");
316 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
317 		err(EXIT_FAILURE, "calloc failed");
318 	sy_buf->gcap = sy_buf->lcap = 64;
319 	st_buf->gcap = 256;
320 	st_buf->lcap = 64;
321 	st_buf->lsz = 1;	/* '\0' at start. */
322 	st_buf->gsz = 0;
323 	nsyms = 0;
324 
325 	ecp->symtab->sz = 0;
326 	ecp->strtab->sz = 0;
327 	ecp->symtab->buf = sy_buf;
328 	ecp->strtab->buf = st_buf;
329 
330 	/*
331 	 * Create bit vector v_secsym, which is used to mark sections
332 	 * that already have corresponding STT_SECTION symbols.
333 	 */
334 	ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
335 	if (ecp->v_secsym == NULL)
336 		err(EXIT_FAILURE, "calloc failed");
337 
338 	/* Locate .strtab of input object. */
339 	symndx = 0;
340 	name = NULL;
341 	is = NULL;
342 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
343 		if (gelf_getshdr(is, &ish) != &ish)
344 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
345 			    elf_errmsg(-1));
346 		if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
347 		    NULL)
348 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
349 			    elf_errmsg(-1));
350 		if (strcmp(name, ".strtab") == 0) {
351 			symndx = elf_ndxscn(is);
352 			break;
353 		}
354 	}
355 	elferr = elf_errno();
356 	if (elferr != 0)
357 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
358 		    elf_errmsg(elferr));
359 
360 	/* Symbol table should exist if this function is called. */
361 	if (symndx == 0) {
362 		warnx("can't find .strtab section");
363 		return (0);
364 	}
365 
366 	/* Locate .symtab of input object. */
367 	is = NULL;
368 	while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
369 		if (gelf_getshdr(is, &ish) != &ish)
370 			errx(EXIT_FAILURE, "elf_getshdr failed: %s",
371 			    elf_errmsg(-1));
372 		if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
373 		    NULL)
374 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
375 			    elf_errmsg(-1));
376 		if (strcmp(name, ".symtab") == 0)
377 			break;
378 	}
379 	elferr = elf_errno();
380 	if (elferr != 0)
381 		errx(EXIT_FAILURE, "elf_nextscn failed: %s",
382 		    elf_errmsg(elferr));
383 	if (is == NULL)
384 		errx(EXIT_FAILURE, "can't find .strtab section");
385 
386 	/*
387 	 * Create bit vector gsym to mark global symbols, and symndx
388 	 * to keep track of symbol index changes from input object to
389 	 * output object, it is used by update_reloc() later to update
390 	 * relocation information.
391 	 */
392 	gsym = NULL;
393 	sc = ish.sh_size / ish.sh_entsize;
394 	if (sc > 0) {
395 		ecp->symndx = calloc(sc, sizeof(*ecp->symndx));
396 		if (ecp->symndx == NULL)
397 			err(EXIT_FAILURE, "calloc failed");
398 		gsym = calloc((sc + 7) / 8, sizeof(*gsym));
399 		if (gsym == NULL)
400 			err(EXIT_FAILURE, "calloc failed");
401 		if ((id = elf_getdata(is, NULL)) == NULL) {
402 			elferr = elf_errno();
403 			if (elferr != 0)
404 				errx(EXIT_FAILURE, "elf_getdata failed: %s",
405 				    elf_errmsg(elferr));
406 			return (0);
407 		}
408 	} else
409 		return (0);
410 
411 	/* Copy/Filter each symbol. */
412 	for (i = 0; (size_t)i < sc; i++) {
413 		if (gelf_getsym(id, i, &sym) != &sym)
414 			errx(EXIT_FAILURE, "gelf_getsym failed: %s",
415 			    elf_errmsg(-1));
416 		if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
417 			errx(EXIT_FAILURE, "elf_strptr failed: %s",
418 			    elf_errmsg(-1));
419 
420 		/* Symbol filtering. */
421 		if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
422 			continue;
423 
424 		/* Check if we need to change the binding of this symbol. */
425 		if (is_global_symbol(sym.st_info) ||
426 		    is_weak_symbol(sym.st_info)) {
427 			/*
428 			 * XXX Binutils objcopy does not weaken certain
429 			 * symbols.
430 			 */
431 			if (ecp->flags & WEAKEN_ALL ||
432 			    lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL)
433 				sym.st_info = GELF_ST_INFO(STB_WEAK,
434 				    GELF_ST_TYPE(sym.st_info));
435 			/* Do not localize undefined symbols. */
436 			if (sym.st_shndx != SHN_UNDEF &&
437 			    lookup_symop_list(ecp, name, SYMOP_LOCALIZE) !=
438 			    NULL)
439 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
440 				    GELF_ST_TYPE(sym.st_info));
441 			if (ecp->flags & KEEP_GLOBAL &&
442 			    sym.st_shndx != SHN_UNDEF &&
443 			    lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL)
444 				sym.st_info = GELF_ST_INFO(STB_LOCAL,
445 				    GELF_ST_TYPE(sym.st_info));
446 		} else {
447 			/* STB_LOCAL binding. */
448 			if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
449 			    NULL)
450 				sym.st_info = GELF_ST_INFO(STB_GLOBAL,
451 				    GELF_ST_TYPE(sym.st_info));
452 			/* XXX We should globalize weak symbol? */
453 		}
454 
455 		/* Check if we need to rename this symbol. */
456 		if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
457 			name = sp->newname;
458 
459 		/* Check if we need to prefix the symbols. */
460 		newname = NULL;
461 		if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') {
462 			namelen = strlen(name) + strlen(ecp->prefix_sym) + 1;
463 			if ((newname = malloc(namelen)) == NULL)
464 				err(EXIT_FAILURE, "malloc failed");
465 			snprintf(newname, namelen, "%s%s", ecp->prefix_sym,
466 			    name);
467 			name = newname;
468 		}
469 
470 		/* Copy symbol, mark global/weak symbol and add to index map. */
471 		if (is_global_symbol(sym.st_info) ||
472 		    is_weak_symbol(sym.st_info)) {
473 			BIT_SET(gsym, i);
474 			ecp->symndx[i] = sy_buf->ngs;
475 		} else
476 			ecp->symndx[i] = sy_buf->nls;
477 		add_to_symtab(ecp, name, sym.st_value, sym.st_size,
478 		    sym.st_shndx, sym.st_info, sym.st_other, 0);
479 
480 		if (newname != NULL)
481 			free(newname);
482 
483 		/*
484 		 * If the symbol is a STT_SECTION symbol, mark the section
485 		 * it points to.
486 		 */
487 		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION)
488 			BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]);
489 	}
490 
491 	/*
492 	 * Give up if there is no real symbols inside the table.
493 	 * XXX The logic here needs to be improved. We need to
494 	 * check if that only local symbol is the reserved symbol.
495 	 */
496 	if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
497 		return (0);
498 
499 	/*
500 	 * Create STT_SECTION symbols for sections that do not already
501 	 * got one. However, we do not create STT_SECTION symbol for
502 	 * .symtab, .strtab, .shstrtab and reloc sec of relocatables.
503 	 */
504 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
505 		if (s->pseudo)
506 			continue;
507 		if (strcmp(s->name, ".symtab") == 0 ||
508 		    strcmp(s->name, ".strtab") == 0 ||
509 		    strcmp(s->name, ".shstrtab") == 0)
510 			continue;
511 		if ((ecp->flags & RELOCATABLE) != 0 &&
512 		    ((s->type == SHT_REL) || (s->type == SHT_RELA)))
513 			continue;
514 
515 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
516 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
517 			    elf_errmsg(-1));
518 
519 		if (!BIT_ISSET(ecp->v_secsym, ndx)) {
520 			sym.st_name  = 0;
521 			sym.st_value = s->vma;
522 			sym.st_size  = 0;
523 			sym.st_info  = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
524 			/*
525 			 * Don't let add_to_symtab() touch sym.st_shndx.
526 			 * In this case, we know the index already.
527 			 */
528 			add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
529 			    ndx, sym.st_info, sym.st_other, 1);
530 		}
531 	}
532 
533 	/*
534 	 * Update st_name and index map for global/weak symbols. Note that
535 	 * global/weak symbols are put after local symbols.
536 	 */
537 	if (gsym != NULL) {
538 		for(i = 0; (size_t) i < sc; i++) {
539 			if (!BIT_ISSET(gsym, i))
540 				continue;
541 
542 			/* Update st_name. */
543 			if (ec == ELFCLASS32)
544 				sy_buf->g32[ecp->symndx[i]].st_name +=
545 				    st_buf->lsz;
546 			else
547 				sy_buf->g64[ecp->symndx[i]].st_name +=
548 				    st_buf->lsz;
549 
550 			/* Update index map. */
551 			ecp->symndx[i] += sy_buf->nls;
552 		}
553 		free(gsym);
554 	}
555 
556 	return (1);
557 }
558 
559 void
560 create_symtab(struct elfcopy *ecp)
561 {
562 	struct section	*s, *sy, *st;
563 	size_t		 maxndx, ndx;
564 
565 	sy = ecp->symtab;
566 	st = ecp->strtab;
567 
568 	/*
569 	 * Set section index map for .symtab and .strtab. We need to set
570 	 * these map because otherwise symbols which refer to .symtab and
571 	 * .strtab will be removed by symbol filtering unconditionally.
572 	 * And we have to figure out scn index this way (instead of calling
573 	 * elf_ndxscn) because we can not create Elf_Scn before we're certain
574 	 * that .symtab and .strtab will exist in the output object.
575 	 */
576 	maxndx = 0;
577 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
578 		if (s->os == NULL)
579 			continue;
580 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
581 			errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
582 			    elf_errmsg(-1));
583 		if (ndx > maxndx)
584 			maxndx = ndx;
585 	}
586 	ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
587 	ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
588 
589 	/*
590 	 * Generate symbols for output object if SYMTAB_INTACT is not set.
591 	 * If there is no symbol in the input object or all the symbols are
592 	 * stripped, then free all the resouces allotted for symbol table,
593 	 * and clear SYMTAB_EXIST flag.
594 	 */
595 	if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
596 		TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
597 		TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
598 		free(ecp->symtab);
599 		free(ecp->strtab);
600 		ecp->symtab = NULL;
601 		ecp->strtab = NULL;
602 		ecp->flags &= ~SYMTAB_EXIST;
603 		return;
604 	}
605 
606 	/* Create output Elf_Scn for .symtab and .strtab. */
607 	if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
608 	    (st->os = elf_newscn(ecp->eout)) == NULL)
609 		errx(EXIT_FAILURE, "elf_newscn failed: %s",
610 		    elf_errmsg(-1));
611 	/* Update secndx anyway. */
612 	ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
613 	ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
614 
615 	/*
616 	 * Copy .symtab and .strtab section headers from input to output
617 	 * object to start with, these will be overridden later if need.
618 	 */
619 	copy_shdr(ecp, sy, ".symtab", 1, 0);
620 	copy_shdr(ecp, st, ".strtab", 1, 0);
621 
622 	/* Copy verbatim if symbol table is intact. */
623 	if (ecp->flags & SYMTAB_INTACT) {
624 		copy_data(sy);
625 		copy_data(st);
626 		return;
627 	}
628 
629 	create_symtab_data(ecp);
630 }
631 
632 void
633 free_symtab(struct elfcopy *ecp)
634 {
635 	struct symbuf	*sy_buf;
636 	struct strbuf	*st_buf;
637 
638 	if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
639 		sy_buf = ecp->symtab->buf;
640 		if (sy_buf->l32 != NULL)
641 			free(sy_buf->l32);
642 		if (sy_buf->g32 != NULL)
643 			free(sy_buf->g32);
644 		if (sy_buf->l64 != NULL)
645 			free(sy_buf->l64);
646 		if (sy_buf->g64 != NULL)
647 			free(sy_buf->g64);
648 	}
649 
650 	if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
651 		st_buf = ecp->strtab->buf;
652 		if (st_buf->l != NULL)
653 			free(st_buf->l);
654 		if (st_buf->g != NULL)
655 			free(st_buf->g);
656 	}
657 }
658 
659 void
660 create_external_symtab(struct elfcopy *ecp)
661 {
662 	struct section *s;
663 	struct symbuf *sy_buf;
664 	struct strbuf *st_buf;
665 	GElf_Shdr sh;
666 	size_t ndx;
667 
668 	if (ecp->oec == ELFCLASS32)
669 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
670 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
671 	else
672 		ecp->symtab = create_external_section(ecp, ".symtab", NULL,
673 		    NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
674 
675 	ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
676 	    SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
677 
678 	/* Let sh_link field of .symtab section point to .strtab section. */
679 	if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
680 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
681 		    elf_errmsg(-1));
682 	sh.sh_link = elf_ndxscn(ecp->strtab->os);
683 	if (!gelf_update_shdr(ecp->symtab->os, &sh))
684 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
685 		    elf_errmsg(-1));
686 
687 	/* Create buffers for .symtab and .strtab. */
688 	if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
689 		err(EXIT_FAILURE, "calloc failed");
690 	if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
691 		err(EXIT_FAILURE, "calloc failed");
692 	sy_buf->gcap = sy_buf->lcap = 64;
693 	st_buf->gcap = 256;
694 	st_buf->lcap = 64;
695 	st_buf->lsz = 1;	/* '\0' at start. */
696 	st_buf->gsz = 0;
697 
698 	ecp->symtab->sz = 0;
699 	ecp->strtab->sz = 0;
700 	ecp->symtab->buf = sy_buf;
701 	ecp->strtab->buf = st_buf;
702 
703 	/* Always create the special symbol at the symtab beginning. */
704 	add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
705 	    ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
706 
707 	/* Create STT_SECTION symbols. */
708 	TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
709 		if (s->pseudo)
710 			continue;
711 		if (strcmp(s->name, ".symtab") == 0 ||
712 		    strcmp(s->name, ".strtab") == 0 ||
713 		    strcmp(s->name, ".shstrtab") == 0)
714 			continue;
715 		(void) elf_errno();
716 		if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
717 			warnx("elf_ndxscn failed: %s",
718 			    elf_errmsg(-1));
719 			continue;
720 		}
721 		add_to_symtab(ecp, NULL, 0, 0, ndx,
722 		    GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
723 	}
724 }
725 
726 void
727 add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
728     uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
729     unsigned char st_other, int ndx_known)
730 {
731 	struct symbuf *sy_buf;
732 	struct strbuf *st_buf;
733 	int pos;
734 
735 	/*
736 	 * Convenient macro for copying global/local 32/64 bit symbols
737 	 * from input object to the buffer created for output object.
738 	 * It handles buffer growing, st_name calculating and st_shndx
739 	 * updating for symbols with non-special section index.
740 	 */
741 #define	_ADDSYM(B, SZ) do {						\
742 	if (sy_buf->B##SZ == NULL) {					\
743 		sy_buf->B##SZ = malloc(sy_buf->B##cap *			\
744 		    sizeof(Elf##SZ##_Sym));				\
745 		if (sy_buf->B##SZ == NULL)				\
746 			err(EXIT_FAILURE, "malloc failed");		\
747 	} else if (sy_buf->n##B##s >= sy_buf->B##cap) {			\
748 		sy_buf->B##cap *= 2;					\
749 		sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap *	\
750 		    sizeof(Elf##SZ##_Sym));				\
751 		if (sy_buf->B##SZ == NULL)				\
752 			err(EXIT_FAILURE, "realloc failed");		\
753 	}								\
754 	sy_buf->B##SZ[sy_buf->n##B##s].st_info	= st_info;		\
755 	sy_buf->B##SZ[sy_buf->n##B##s].st_other	= st_other;		\
756 	sy_buf->B##SZ[sy_buf->n##B##s].st_value	= st_value;		\
757 	sy_buf->B##SZ[sy_buf->n##B##s].st_size	= st_size;		\
758 	if (ndx_known)							\
759 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
760 	else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE)	\
761 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;	\
762 	else								\
763 		sy_buf->B##SZ[sy_buf->n##B##s].st_shndx	=		\
764 			ecp->secndx[st_shndx];				\
765 	if (st_buf->B == NULL) {					\
766 		st_buf->B = calloc(st_buf->B##cap, sizeof(*st_buf->B));	\
767 		if (st_buf->B == NULL)					\
768 			err(EXIT_FAILURE, "malloc failed");		\
769 	}								\
770 	if (name != NULL && *name != '\0') {				\
771 		pos = lookup_exact_string(st_buf->B,			\
772 		    st_buf->B##sz, name);				\
773 		if (pos != -1)						\
774 			sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos;	\
775 		else {							\
776 			sy_buf->B##SZ[sy_buf->n##B##s].st_name =	\
777 			    st_buf->B##sz;				\
778 			while (st_buf->B##sz + strlen(name) >=		\
779 			    st_buf->B##cap - 1) {			\
780 				st_buf->B##cap *= 2;			\
781 				st_buf->B = realloc(st_buf->B,		\
782 				    st_buf->B##cap);			\
783 				if (st_buf->B == NULL)			\
784 					err(EXIT_FAILURE,		\
785 					    "realloc failed");		\
786 			}						\
787 			strncpy(&st_buf->B[st_buf->B##sz], name,	\
788 			    strlen(name));				\
789 			st_buf->B[st_buf->B##sz + strlen(name)] = '\0';	\
790 			st_buf->B##sz += strlen(name) + 1;		\
791 		}							\
792 	} else								\
793 		sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0;		\
794 	sy_buf->n##B##s++;						\
795 } while (0)
796 
797 	sy_buf = ecp->symtab->buf;
798 	st_buf = ecp->strtab->buf;
799 
800 	if (ecp->oec == ELFCLASS32) {
801 		if (is_local_symbol(st_info))
802 			_ADDSYM(l, 32);
803 		else
804 			_ADDSYM(g, 32);
805 	} else {
806 		if (is_local_symbol(st_info))
807 			_ADDSYM(l, 64);
808 		else
809 			_ADDSYM(g, 64);
810 	}
811 
812 	/* Update section size. */
813 	ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
814 	    (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
815 	ecp->strtab->sz = st_buf->lsz + st_buf->gsz;
816 
817 #undef	_ADDSYM
818 }
819 
820 void
821 finalize_external_symtab(struct elfcopy *ecp)
822 {
823 	struct symbuf *sy_buf;
824 	struct strbuf *st_buf;
825 	int i;
826 
827 	/*
828 	 * Update st_name for global/weak symbols. (global/weak symbols
829 	 * are put after local symbols)
830 	 */
831 	sy_buf = ecp->symtab->buf;
832 	st_buf = ecp->strtab->buf;
833 	for (i = 0; (size_t) i < sy_buf->ngs; i++) {
834 		if (ecp->oec == ELFCLASS32)
835 			sy_buf->g32[i].st_name += st_buf->lsz;
836 		else
837 			sy_buf->g64[i].st_name += st_buf->lsz;
838 	}
839 }
840 
841 void
842 create_symtab_data(struct elfcopy *ecp)
843 {
844 	struct section	*sy, *st;
845 	struct symbuf	*sy_buf;
846 	struct strbuf	*st_buf;
847 	Elf_Data	*gsydata, *lsydata, *gstdata, *lstdata;
848 	GElf_Shdr	 shy, sht;
849 
850 	sy = ecp->symtab;
851 	st = ecp->strtab;
852 
853 	if (gelf_getshdr(sy->os, &shy) == NULL)
854 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
855 		    elf_errmsg(-1));
856 	if (gelf_getshdr(st->os, &sht) == NULL)
857 		errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
858 		    elf_errmsg(-1));
859 
860 	/*
861 	 * Create two Elf_Data for .symtab section of output object, one
862 	 * for local symbols and another for global symbols. Note that
863 	 * local symbols appear first in the .symtab.
864 	 */
865 	sy_buf = sy->buf;
866 	if (sy_buf->nls > 0) {
867 		if ((lsydata = elf_newdata(sy->os)) == NULL)
868 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
869 			     elf_errmsg(-1));
870 		if (ecp->oec == ELFCLASS32) {
871 			lsydata->d_align	= 4;
872 			lsydata->d_off		= 0;
873 			lsydata->d_buf		= sy_buf->l32;
874 			lsydata->d_size		= sy_buf->nls *
875 				sizeof(Elf32_Sym);
876 			lsydata->d_type		= ELF_T_SYM;
877 			lsydata->d_version	= EV_CURRENT;
878 		} else {
879 			lsydata->d_align	= 8;
880 			lsydata->d_off		= 0;
881 			lsydata->d_buf		= sy_buf->l64;
882 			lsydata->d_size		= sy_buf->nls *
883 				sizeof(Elf64_Sym);
884 			lsydata->d_type		= ELF_T_SYM;
885 			lsydata->d_version	= EV_CURRENT;
886 		}
887 	}
888 	if (sy_buf->ngs > 0) {
889 		if ((gsydata = elf_newdata(sy->os)) == NULL)
890 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
891 			     elf_errmsg(-1));
892 		if (ecp->oec == ELFCLASS32) {
893 			gsydata->d_align	= 4;
894 			gsydata->d_off		= sy_buf->nls *
895 				sizeof(Elf32_Sym);
896 			gsydata->d_buf		= sy_buf->g32;
897 			gsydata->d_size		= sy_buf->ngs *
898 				sizeof(Elf32_Sym);
899 			gsydata->d_type		= ELF_T_SYM;
900 			gsydata->d_version	= EV_CURRENT;
901 		} else {
902 			gsydata->d_align	= 8;
903 			gsydata->d_off		= sy_buf->nls *
904 				sizeof(Elf64_Sym);
905 			gsydata->d_buf		= sy_buf->g64;
906 			gsydata->d_size		= sy_buf->ngs *
907 				sizeof(Elf64_Sym);
908 			gsydata->d_type		= ELF_T_SYM;
909 			gsydata->d_version	= EV_CURRENT;
910 		}
911 	}
912 
913 	/*
914 	 * Create two Elf_Data for .strtab, one for local symbol name
915 	 * and another for globals. Same as .symtab, local symbol names
916 	 * appear first.
917 	 */
918 	st_buf = st->buf;
919 	if ((lstdata = elf_newdata(st->os)) == NULL)
920 		errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
921 		    elf_errmsg(-1));
922 	lstdata->d_align	= 1;
923 	lstdata->d_off		= 0;
924 	lstdata->d_buf		= st_buf->l;
925 	lstdata->d_size		= st_buf->lsz;
926 	lstdata->d_type		= ELF_T_BYTE;
927 	lstdata->d_version	= EV_CURRENT;
928 
929 	if (st_buf->gsz > 0) {
930 		if ((gstdata = elf_newdata(st->os)) == NULL)
931 			errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
932 			    elf_errmsg(-1));
933 		gstdata->d_align	= 1;
934 		gstdata->d_off		= lstdata->d_size;
935 		gstdata->d_buf		= st_buf->g;
936 		gstdata->d_size		= st_buf->gsz;
937 		gstdata->d_type		= ELF_T_BYTE;
938 		gstdata->d_version	= EV_CURRENT;
939 	}
940 
941 	shy.sh_addr		= 0;
942 	shy.sh_addralign	= (ecp->oec == ELFCLASS32 ? 4 : 8);
943 	shy.sh_size		= sy->sz;
944 	shy.sh_type		= SHT_SYMTAB;
945 	shy.sh_flags		= 0;
946 	shy.sh_entsize		= gelf_fsize(ecp->eout, ELF_T_SYM, 1,
947 	    EV_CURRENT);
948 	/*
949 	 * According to SYSV abi, here sh_info is one greater than
950 	 * the symbol table index of the last local symbol(binding
951 	 * STB_LOCAL).
952 	 */
953 	shy.sh_info		= sy_buf->nls;
954 
955 	sht.sh_addr		= 0;
956 	sht.sh_addralign	= 1;
957 	sht.sh_size		= st->sz;
958 	sht.sh_type		= SHT_STRTAB;
959 	sht.sh_flags		= 0;
960 	sht.sh_entsize		= 0;
961 	sht.sh_info		= 0;
962 	sht.sh_link		= 0;
963 
964 	if (!gelf_update_shdr(sy->os, &shy))
965 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
966 		    elf_errmsg(-1));
967 	if (!gelf_update_shdr(st->os, &sht))
968 		errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
969 		    elf_errmsg(-1));
970 }
971 
972 void
973 add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
974     unsigned int op)
975 {
976 	struct symop *s;
977 
978 	if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) {
979 		if ((s = calloc(1, sizeof(*s))) == NULL)
980 			errx(EXIT_FAILURE, "not enough memory");
981 		s->name = name;
982 		if (op == SYMOP_REDEF)
983 			s->newname = newname;
984 	}
985 
986 	s->op |= op;
987 	STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
988 }
989 
990 static int
991 match_wildcard(const char *name, const char *pattern)
992 {
993 	int reverse, match;
994 
995 	reverse = 0;
996 	if (*pattern == '!') {
997 		reverse = 1;
998 		pattern++;
999 	}
1000 
1001 	match = 0;
1002 	if (!fnmatch(pattern, name, 0)) {
1003 		match = 1;
1004 		printf("string '%s' match to pattern '%s'\n", name, pattern);
1005 	}
1006 
1007 	return (reverse ? !match : match);
1008 }
1009 
1010 struct symop *
1011 lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1012 {
1013 	struct symop *s;
1014 
1015 	STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1016 		if (name == NULL || !strcmp(name, s->name) ||
1017 		    ((ecp->flags & WILDCARD) && match_wildcard(name, s->name)))
1018 			if ((s->op & op) != 0)
1019 				return (s);
1020 	}
1021 
1022 	return (NULL);
1023 }
1024 
1025 static int
1026 lookup_exact_string(const char *buf, size_t sz, const char *s)
1027 {
1028 	const char	*b;
1029 	size_t		 slen;
1030 
1031 	slen = strlen(s);
1032 	for (b = buf; b < buf + sz; b += strlen(b) + 1) {
1033 		if (strlen(b) != slen)
1034 			continue;
1035 		if (!strcmp(b, s))
1036 			return (b - buf);
1037 	}
1038 
1039 	return (-1);
1040 }
1041