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