]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/elfcopy/symbols.c
Update elftoolchain to upstream rev 3130
[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/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 3019 2014-04-17 14:53:40Z jkoshy $");
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, 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
324         ecp->symtab->sz = 0;
325         ecp->strtab->sz = 0;
326         ecp->symtab->buf = sy_buf;
327         ecp->strtab->buf = st_buf;
328
329         /*
330          * Create bit vector v_secsym, which is used to mark sections
331          * that already have corresponding STT_SECTION symbols.
332          */
333         ecp->v_secsym = calloc((ecp->nos + 7) / 8, 1);
334         if (ecp->v_secsym == NULL)
335                 err(EXIT_FAILURE, "calloc failed");
336
337         /* Locate .strtab of input object. */
338         symndx = 0;
339         name = NULL;
340         is = NULL;
341         while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
342                 if (gelf_getshdr(is, &ish) != &ish)
343                         errx(EXIT_FAILURE, "elf_getshdr failed: %s",
344                             elf_errmsg(-1));
345                 if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
346                     NULL)
347                         errx(EXIT_FAILURE, "elf_strptr failed: %s",
348                             elf_errmsg(-1));
349                 if (strcmp(name, ".strtab") == 0) {
350                         symndx = elf_ndxscn(is);
351                         break;
352                 }
353         }
354         elferr = elf_errno();
355         if (elferr != 0)
356                 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
357                     elf_errmsg(elferr));
358
359         /* Symbol table should exist if this function is called. */
360         if (symndx == 0) {
361                 warnx("can't find .strtab section");
362                 return (0);
363         }
364
365         /* Locate .symtab of input object. */
366         is = NULL;
367         while ((is = elf_nextscn(ecp->ein, is)) != NULL) {
368                 if (gelf_getshdr(is, &ish) != &ish)
369                         errx(EXIT_FAILURE, "elf_getshdr failed: %s",
370                             elf_errmsg(-1));
371                 if ((name = elf_strptr(ecp->ein, ishstrndx, ish.sh_name)) ==
372                     NULL)
373                         errx(EXIT_FAILURE, "elf_strptr failed: %s",
374                             elf_errmsg(-1));
375                 if (strcmp(name, ".symtab") == 0)
376                         break;
377         }
378         elferr = elf_errno();
379         if (elferr != 0)
380                 errx(EXIT_FAILURE, "elf_nextscn failed: %s",
381                     elf_errmsg(elferr));
382         if (is == NULL)
383                 errx(EXIT_FAILURE, "can't find .strtab section");
384
385         /*
386          * Create bit vector gsym to mark global symbols, and symndx
387          * to keep track of symbol index changes from input object to
388          * output object, it is used by update_reloc() later to update
389          * relocation information.
390          */
391         gsym = NULL;
392         sc = ish.sh_size / ish.sh_entsize;
393         if (sc > 0) {
394                 ecp->symndx = calloc(sc, sizeof(*ecp->symndx));
395                 if (ecp->symndx == NULL)
396                         err(EXIT_FAILURE, "calloc failed");
397                 gsym = calloc((sc + 7) / 8, sizeof(*gsym));
398                 if (gsym == NULL)
399                         err(EXIT_FAILURE, "calloc failed");
400                 if ((id = elf_getdata(is, NULL)) == NULL) {
401                         elferr = elf_errno();
402                         if (elferr != 0)
403                                 errx(EXIT_FAILURE, "elf_getdata failed: %s",
404                                     elf_errmsg(elferr));
405                         return (0);
406                 }
407         } else
408                 return (0);
409
410         /* Copy/Filter each symbol. */
411         for (i = 0; (size_t)i < sc; i++) {
412                 if (gelf_getsym(id, i, &sym) != &sym)
413                         errx(EXIT_FAILURE, "gelf_getsym failed: %s",
414                             elf_errmsg(-1));
415                 if ((name = elf_strptr(ecp->ein, symndx, sym.st_name)) == NULL)
416                         errx(EXIT_FAILURE, "elf_strptr failed: %s",
417                             elf_errmsg(-1));
418
419                 /* Symbol filtering. */
420                 if (is_remove_symbol(ecp, sc, i, &sym, name) != 0)
421                         continue;
422
423                 /* Check if we need to change the binding of this symbol. */
424                 if (is_global_symbol(sym.st_info) ||
425                     is_weak_symbol(sym.st_info)) {
426                         /*
427                          * XXX Binutils objcopy does not weaken certain
428                          * symbols.
429                          */
430                         if (ecp->flags & WEAKEN_ALL ||
431                             lookup_symop_list(ecp, name, SYMOP_WEAKEN) != NULL)
432                                 sym.st_info = GELF_ST_INFO(STB_WEAK,
433                                     GELF_ST_TYPE(sym.st_info));
434                         /* Do not localize undefined symbols. */
435                         if (sym.st_shndx != SHN_UNDEF &&
436                             lookup_symop_list(ecp, name, SYMOP_LOCALIZE) !=
437                             NULL)
438                                 sym.st_info = GELF_ST_INFO(STB_LOCAL,
439                                     GELF_ST_TYPE(sym.st_info));
440                         if (ecp->flags & KEEP_GLOBAL &&
441                             sym.st_shndx != SHN_UNDEF &&
442                             lookup_symop_list(ecp, name, SYMOP_KEEPG) == NULL)
443                                 sym.st_info = GELF_ST_INFO(STB_LOCAL,
444                                     GELF_ST_TYPE(sym.st_info));
445                 } else {
446                         /* STB_LOCAL binding. */
447                         if (lookup_symop_list(ecp, name, SYMOP_GLOBALIZE) !=
448                             NULL)
449                                 sym.st_info = GELF_ST_INFO(STB_GLOBAL,
450                                     GELF_ST_TYPE(sym.st_info));
451                         /* XXX We should globalize weak symbol? */
452                 }
453
454                 /* Check if we need to rename this symbol. */
455                 if ((sp = lookup_symop_list(ecp, name, SYMOP_REDEF)) != NULL)
456                         name = sp->newname;
457
458                 /* Check if we need to prefix the symbols. */
459                 newname = NULL;
460                 if (ecp->prefix_sym != NULL && name != NULL && *name != '\0') {
461                         namelen = strlen(name) + strlen(ecp->prefix_sym) + 1;
462                         if ((newname = malloc(namelen)) == NULL)
463                                 err(EXIT_FAILURE, "malloc failed");
464                         snprintf(newname, namelen, "%s%s", ecp->prefix_sym,
465                             name);
466                         name = newname;
467                 }
468
469                 /* Copy symbol, mark global/weak symbol and add to index map. */
470                 if (is_global_symbol(sym.st_info) ||
471                     is_weak_symbol(sym.st_info)) {
472                         BIT_SET(gsym, i);
473                         ecp->symndx[i] = sy_buf->ngs;
474                 } else
475                         ecp->symndx[i] = sy_buf->nls;
476                 add_to_symtab(ecp, name, sym.st_value, sym.st_size,
477                     sym.st_shndx, sym.st_info, sym.st_other, 0);
478
479                 if (newname != NULL)
480                         free(newname);
481
482                 /*
483                  * If the symbol is a STT_SECTION symbol, mark the section
484                  * it points to.
485                  */
486                 if (GELF_ST_TYPE(sym.st_info) == STT_SECTION)
487                         BIT_SET(ecp->v_secsym, ecp->secndx[sym.st_shndx]);
488         }
489
490         /*
491          * Give up if there is no real symbols inside the table.
492          * XXX The logic here needs to be improved. We need to
493          * check if that only local symbol is the reserved symbol.
494          */
495         if (sy_buf->nls <= 1 && sy_buf->ngs == 0)
496                 return (0);
497
498         /*
499          * Create STT_SECTION symbols for sections that do not already
500          * got one. However, we do not create STT_SECTION symbol for
501          * .symtab, .strtab, .shstrtab and reloc sec of relocatables.
502          */
503         TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
504                 if (s->pseudo)
505                         continue;
506                 if (strcmp(s->name, ".symtab") == 0 ||
507                     strcmp(s->name, ".strtab") == 0 ||
508                     strcmp(s->name, ".shstrtab") == 0)
509                         continue;
510                 if ((ecp->flags & RELOCATABLE) != 0 &&
511                     ((s->type == SHT_REL) || (s->type == SHT_RELA)))
512                         continue;
513
514                 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
515                         errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
516                             elf_errmsg(-1));
517
518                 if (!BIT_ISSET(ecp->v_secsym, ndx)) {
519                         sym.st_name  = 0;
520                         sym.st_value = s->vma;
521                         sym.st_size  = 0;
522                         sym.st_info  = GELF_ST_INFO(STB_LOCAL, STT_SECTION);
523                         /*
524                          * Don't let add_to_symtab() touch sym.st_shndx.
525                          * In this case, we know the index already.
526                          */
527                         add_to_symtab(ecp, NULL, sym.st_value, sym.st_size,
528                             ndx, sym.st_info, sym.st_other, 1);
529                 }
530         }
531
532         /*
533          * Update st_name and index map for global/weak symbols. Note that
534          * global/weak symbols are put after local symbols.
535          */
536         if (gsym != NULL) {
537                 for(i = 0; (size_t) i < sc; i++) {
538                         if (!BIT_ISSET(gsym, i))
539                                 continue;
540
541                         /* Update st_name. */
542                         if (ec == ELFCLASS32)
543                                 sy_buf->g32[ecp->symndx[i]].st_name +=
544                                     st_buf->lsz;
545                         else
546                                 sy_buf->g64[ecp->symndx[i]].st_name +=
547                                     st_buf->lsz;
548
549                         /* Update index map. */
550                         ecp->symndx[i] += sy_buf->nls;
551                 }
552                 free(gsym);
553         }
554
555         return (1);
556 }
557
558 void
559 create_symtab(struct elfcopy *ecp)
560 {
561         struct section  *s, *sy, *st;
562         size_t           maxndx, ndx;
563
564         sy = ecp->symtab;
565         st = ecp->strtab;
566
567         /*
568          * Set section index map for .symtab and .strtab. We need to set
569          * these map because otherwise symbols which refer to .symtab and
570          * .strtab will be removed by symbol filtering unconditionally.
571          * And we have to figure out scn index this way (instead of calling
572          * elf_ndxscn) because we can not create Elf_Scn before we're certain
573          * that .symtab and .strtab will exist in the output object.
574          */
575         maxndx = 0;
576         TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
577                 if (s->os == NULL)
578                         continue;
579                 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF)
580                         errx(EXIT_FAILURE, "elf_ndxscn failed: %s",
581                             elf_errmsg(-1));
582                 if (ndx > maxndx)
583                         maxndx = ndx;
584         }
585         ecp->secndx[elf_ndxscn(sy->is)] = maxndx + 1;
586         ecp->secndx[elf_ndxscn(st->is)] = maxndx + 2;
587
588         /*
589          * Generate symbols for output object if SYMTAB_INTACT is not set.
590          * If there is no symbol in the input object or all the symbols are
591          * stripped, then free all the resouces allotted for symbol table,
592          * and clear SYMTAB_EXIST flag.
593          */
594         if (((ecp->flags & SYMTAB_INTACT) == 0) && !generate_symbols(ecp)) {
595                 TAILQ_REMOVE(&ecp->v_sec, ecp->symtab, sec_list);
596                 TAILQ_REMOVE(&ecp->v_sec, ecp->strtab, sec_list);
597                 free(ecp->symtab);
598                 free(ecp->strtab);
599                 ecp->symtab = NULL;
600                 ecp->strtab = NULL;
601                 ecp->flags &= ~SYMTAB_EXIST;
602                 return;
603         }
604
605         /* Create output Elf_Scn for .symtab and .strtab. */
606         if ((sy->os = elf_newscn(ecp->eout)) == NULL ||
607             (st->os = elf_newscn(ecp->eout)) == NULL)
608                 errx(EXIT_FAILURE, "elf_newscn failed: %s",
609                     elf_errmsg(-1));
610         /* Update secndx anyway. */
611         ecp->secndx[elf_ndxscn(sy->is)] = elf_ndxscn(sy->os);
612         ecp->secndx[elf_ndxscn(st->is)] = elf_ndxscn(st->os);
613
614         /*
615          * Copy .symtab and .strtab section headers from input to output
616          * object to start with, these will be overridden later if need.
617          */
618         copy_shdr(ecp, sy, ".symtab", 1, 0);
619         copy_shdr(ecp, st, ".strtab", 1, 0);
620
621         /* Copy verbatim if symbol table is intact. */
622         if (ecp->flags & SYMTAB_INTACT) {
623                 copy_data(sy);
624                 copy_data(st);
625                 return;
626         }
627
628         create_symtab_data(ecp);
629 }
630
631 void
632 free_symtab(struct elfcopy *ecp)
633 {
634         struct symbuf   *sy_buf;
635         struct strbuf   *st_buf;
636
637         if (ecp->symtab != NULL && ecp->symtab->buf != NULL) {
638                 sy_buf = ecp->symtab->buf;
639                 if (sy_buf->l32 != NULL)
640                         free(sy_buf->l32);
641                 if (sy_buf->g32 != NULL)
642                         free(sy_buf->g32);
643                 if (sy_buf->l64 != NULL)
644                         free(sy_buf->l64);
645                 if (sy_buf->g64 != NULL)
646                         free(sy_buf->g64);
647         }
648
649         if (ecp->strtab != NULL && ecp->strtab->buf != NULL) {
650                 st_buf = ecp->strtab->buf;
651                 if (st_buf->l != NULL)
652                         free(st_buf->l);
653                 if (st_buf->g != NULL)
654                         free(st_buf->g);
655         }
656 }
657
658 void
659 create_external_symtab(struct elfcopy *ecp)
660 {
661         struct section *s;
662         struct symbuf *sy_buf;
663         struct strbuf *st_buf;
664         GElf_Shdr sh;
665         size_t ndx;
666
667         if (ecp->oec == ELFCLASS32)
668                 ecp->symtab = create_external_section(ecp, ".symtab", NULL,
669                     NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 4, 0, 0);
670         else
671                 ecp->symtab = create_external_section(ecp, ".symtab", NULL,
672                     NULL, 0, 0, SHT_SYMTAB, ELF_T_SYM, 0, 8, 0, 0);
673
674         ecp->strtab = create_external_section(ecp, ".strtab", NULL, NULL, 0, 0,
675             SHT_STRTAB, ELF_T_BYTE, 0, 1, 0, 0);
676
677         /* Let sh_link field of .symtab section point to .strtab section. */
678         if (gelf_getshdr(ecp->symtab->os, &sh) == NULL)
679                 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
680                     elf_errmsg(-1));
681         sh.sh_link = elf_ndxscn(ecp->strtab->os);
682         if (!gelf_update_shdr(ecp->symtab->os, &sh))
683                 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
684                     elf_errmsg(-1));
685
686         /* Create buffers for .symtab and .strtab. */
687         if ((sy_buf = calloc(1, sizeof(*sy_buf))) == NULL)
688                 err(EXIT_FAILURE, "calloc failed");
689         if ((st_buf = calloc(1, sizeof(*st_buf))) == NULL)
690                 err(EXIT_FAILURE, "calloc failed");
691         sy_buf->gcap = sy_buf->lcap = 64;
692         st_buf->gcap = 256;
693         st_buf->lcap = 64;
694         st_buf->lsz = 1;        /* '\0' at start. */
695         st_buf->gsz = 0;
696
697         ecp->symtab->sz = 0;
698         ecp->strtab->sz = 0;
699         ecp->symtab->buf = sy_buf;
700         ecp->strtab->buf = st_buf;
701
702         /* Always create the special symbol at the symtab beginning. */
703         add_to_symtab(ecp, NULL, 0, 0, SHN_UNDEF,
704             ELF32_ST_INFO(STB_LOCAL, STT_NOTYPE), 0, 1);
705
706         /* Create STT_SECTION symbols. */
707         TAILQ_FOREACH(s, &ecp->v_sec, sec_list) {
708                 if (s->pseudo)
709                         continue;
710                 if (strcmp(s->name, ".symtab") == 0 ||
711                     strcmp(s->name, ".strtab") == 0 ||
712                     strcmp(s->name, ".shstrtab") == 0)
713                         continue;
714                 (void) elf_errno();
715                 if ((ndx = elf_ndxscn(s->os)) == SHN_UNDEF) {
716                         warnx("elf_ndxscn failed: %s",
717                             elf_errmsg(-1));
718                         continue;
719                 }
720                 add_to_symtab(ecp, NULL, 0, 0, ndx,
721                     GELF_ST_INFO(STB_LOCAL, STT_SECTION), 0, 1);
722         }
723 }
724
725 void
726 add_to_symtab(struct elfcopy *ecp, const char *name, uint64_t st_value,
727     uint64_t st_size, uint16_t st_shndx, unsigned char st_info,
728     unsigned char st_other, int ndx_known)
729 {
730         struct symbuf *sy_buf;
731         struct strbuf *st_buf;
732         int pos;
733
734         /*
735          * Convenient macro for copying global/local 32/64 bit symbols
736          * from input object to the buffer created for output object.
737          * It handles buffer growing, st_name calculating and st_shndx
738          * updating for symbols with non-special section index.
739          */
740 #define _ADDSYM(B, SZ) do {                                             \
741         if (sy_buf->B##SZ == NULL) {                                    \
742                 sy_buf->B##SZ = malloc(sy_buf->B##cap *                 \
743                     sizeof(Elf##SZ##_Sym));                             \
744                 if (sy_buf->B##SZ == NULL)                              \
745                         err(EXIT_FAILURE, "malloc failed");             \
746         } else if (sy_buf->n##B##s >= sy_buf->B##cap) {                 \
747                 sy_buf->B##cap *= 2;                                    \
748                 sy_buf->B##SZ = realloc(sy_buf->B##SZ, sy_buf->B##cap * \
749                     sizeof(Elf##SZ##_Sym));                             \
750                 if (sy_buf->B##SZ == NULL)                              \
751                         err(EXIT_FAILURE, "realloc failed");            \
752         }                                                               \
753         sy_buf->B##SZ[sy_buf->n##B##s].st_info  = st_info;              \
754         sy_buf->B##SZ[sy_buf->n##B##s].st_other = st_other;             \
755         sy_buf->B##SZ[sy_buf->n##B##s].st_value = st_value;             \
756         sy_buf->B##SZ[sy_buf->n##B##s].st_size  = st_size;              \
757         if (ndx_known)                                                  \
758                 sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;     \
759         else if (st_shndx == SHN_UNDEF || st_shndx >= SHN_LORESERVE)    \
760                 sy_buf->B##SZ[sy_buf->n##B##s].st_shndx = st_shndx;     \
761         else                                                            \
762                 sy_buf->B##SZ[sy_buf->n##B##s].st_shndx =               \
763                         ecp->secndx[st_shndx];                          \
764         if (st_buf->B == NULL) {                                        \
765                 st_buf->B = calloc(st_buf->B##cap, sizeof(*st_buf->B)); \
766                 if (st_buf->B == NULL)                                  \
767                         err(EXIT_FAILURE, "malloc failed");             \
768         }                                                               \
769         if (name != NULL && *name != '\0') {                            \
770                 pos = lookup_exact_string(st_buf->B,                    \
771                     st_buf->B##sz, name);                               \
772                 if (pos != -1)                                          \
773                         sy_buf->B##SZ[sy_buf->n##B##s].st_name = pos;   \
774                 else {                                                  \
775                         sy_buf->B##SZ[sy_buf->n##B##s].st_name =        \
776                             st_buf->B##sz;                              \
777                         while (st_buf->B##sz + strlen(name) >=          \
778                             st_buf->B##cap - 1) {                       \
779                                 st_buf->B##cap *= 2;                    \
780                                 st_buf->B = realloc(st_buf->B,          \
781                                     st_buf->B##cap);                    \
782                                 if (st_buf->B == NULL)                  \
783                                         err(EXIT_FAILURE,               \
784                                             "realloc failed");          \
785                         }                                               \
786                         strncpy(&st_buf->B[st_buf->B##sz], name,        \
787                             strlen(name));                              \
788                         st_buf->B[st_buf->B##sz + strlen(name)] = '\0'; \
789                         st_buf->B##sz += strlen(name) + 1;              \
790                 }                                                       \
791         } else                                                          \
792                 sy_buf->B##SZ[sy_buf->n##B##s].st_name = 0;             \
793         sy_buf->n##B##s++;                                              \
794 } while (0)
795
796         sy_buf = ecp->symtab->buf;
797         st_buf = ecp->strtab->buf;
798
799         if (ecp->oec == ELFCLASS32) {
800                 if (is_local_symbol(st_info))
801                         _ADDSYM(l, 32);
802                 else
803                         _ADDSYM(g, 32);
804         } else {
805                 if (is_local_symbol(st_info))
806                         _ADDSYM(l, 64);
807                 else
808                         _ADDSYM(g, 64);
809         }
810
811         /* Update section size. */
812         ecp->symtab->sz = (sy_buf->nls + sy_buf->ngs) *
813             (ecp->oec == ELFCLASS32 ? sizeof(Elf32_Sym) : sizeof(Elf64_Sym));
814         ecp->strtab->sz = st_buf->lsz + st_buf->gsz;
815
816 #undef  _ADDSYM
817 }
818
819 void
820 finalize_external_symtab(struct elfcopy *ecp)
821 {
822         struct symbuf *sy_buf;
823         struct strbuf *st_buf;
824         int i;
825
826         /*
827          * Update st_name for global/weak symbols. (global/weak symbols
828          * are put after local symbols)
829          */
830         sy_buf = ecp->symtab->buf;
831         st_buf = ecp->strtab->buf;
832         for (i = 0; (size_t) i < sy_buf->ngs; i++) {
833                 if (ecp->oec == ELFCLASS32)
834                         sy_buf->g32[i].st_name += st_buf->lsz;
835                 else
836                         sy_buf->g64[i].st_name += st_buf->lsz;
837         }
838 }
839
840 void
841 create_symtab_data(struct elfcopy *ecp)
842 {
843         struct section  *sy, *st;
844         struct symbuf   *sy_buf;
845         struct strbuf   *st_buf;
846         Elf_Data        *gsydata, *lsydata, *gstdata, *lstdata;
847         GElf_Shdr        shy, sht;
848
849         sy = ecp->symtab;
850         st = ecp->strtab;
851
852         if (gelf_getshdr(sy->os, &shy) == NULL)
853                 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
854                     elf_errmsg(-1));
855         if (gelf_getshdr(st->os, &sht) == NULL)
856                 errx(EXIT_FAILURE, "gelf_getshdr() failed: %s",
857                     elf_errmsg(-1));
858
859         /*
860          * Create two Elf_Data for .symtab section of output object, one
861          * for local symbols and another for global symbols. Note that
862          * local symbols appear first in the .symtab.
863          */
864         sy_buf = sy->buf;
865         if (sy_buf->nls > 0) {
866                 if ((lsydata = elf_newdata(sy->os)) == NULL)
867                         errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
868                              elf_errmsg(-1));
869                 if (ecp->oec == ELFCLASS32) {
870                         lsydata->d_align        = 4;
871                         lsydata->d_off          = 0;
872                         lsydata->d_buf          = sy_buf->l32;
873                         lsydata->d_size         = sy_buf->nls *
874                                 sizeof(Elf32_Sym);
875                         lsydata->d_type         = ELF_T_SYM;
876                         lsydata->d_version      = EV_CURRENT;
877                 } else {
878                         lsydata->d_align        = 8;
879                         lsydata->d_off          = 0;
880                         lsydata->d_buf          = sy_buf->l64;
881                         lsydata->d_size         = sy_buf->nls *
882                                 sizeof(Elf64_Sym);
883                         lsydata->d_type         = ELF_T_SYM;
884                         lsydata->d_version      = EV_CURRENT;
885                 }
886         }
887         if (sy_buf->ngs > 0) {
888                 if ((gsydata = elf_newdata(sy->os)) == NULL)
889                         errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
890                              elf_errmsg(-1));
891                 if (ecp->oec == ELFCLASS32) {
892                         gsydata->d_align        = 4;
893                         gsydata->d_off          = sy_buf->nls *
894                                 sizeof(Elf32_Sym);
895                         gsydata->d_buf          = sy_buf->g32;
896                         gsydata->d_size         = sy_buf->ngs *
897                                 sizeof(Elf32_Sym);
898                         gsydata->d_type         = ELF_T_SYM;
899                         gsydata->d_version      = EV_CURRENT;
900                 } else {
901                         gsydata->d_align        = 8;
902                         gsydata->d_off          = sy_buf->nls *
903                                 sizeof(Elf64_Sym);
904                         gsydata->d_buf          = sy_buf->g64;
905                         gsydata->d_size         = sy_buf->ngs *
906                                 sizeof(Elf64_Sym);
907                         gsydata->d_type         = ELF_T_SYM;
908                         gsydata->d_version      = EV_CURRENT;
909                 }
910         }
911
912         /*
913          * Create two Elf_Data for .strtab, one for local symbol name
914          * and another for globals. Same as .symtab, local symbol names
915          * appear first.
916          */
917         st_buf = st->buf;
918         if ((lstdata = elf_newdata(st->os)) == NULL)
919                 errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
920                     elf_errmsg(-1));
921         lstdata->d_align        = 1;
922         lstdata->d_off          = 0;
923         lstdata->d_buf          = st_buf->l;
924         lstdata->d_size         = st_buf->lsz;
925         lstdata->d_type         = ELF_T_BYTE;
926         lstdata->d_version      = EV_CURRENT;
927
928         if (st_buf->gsz > 0) {
929                 if ((gstdata = elf_newdata(st->os)) == NULL)
930                         errx(EXIT_FAILURE, "elf_newdata() failed: %s.",
931                             elf_errmsg(-1));
932                 gstdata->d_align        = 1;
933                 gstdata->d_off          = lstdata->d_size;
934                 gstdata->d_buf          = st_buf->g;
935                 gstdata->d_size         = st_buf->gsz;
936                 gstdata->d_type         = ELF_T_BYTE;
937                 gstdata->d_version      = EV_CURRENT;
938         }
939
940         shy.sh_addr             = 0;
941         shy.sh_addralign        = (ecp->oec == ELFCLASS32 ? 4 : 8);
942         shy.sh_size             = sy->sz;
943         shy.sh_type             = SHT_SYMTAB;
944         shy.sh_flags            = 0;
945         shy.sh_entsize          = gelf_fsize(ecp->eout, ELF_T_SYM, 1,
946             EV_CURRENT);
947         /*
948          * According to SYSV abi, here sh_info is one greater than
949          * the symbol table index of the last local symbol(binding
950          * STB_LOCAL).
951          */
952         shy.sh_info             = sy_buf->nls;
953
954         sht.sh_addr             = 0;
955         sht.sh_addralign        = 1;
956         sht.sh_size             = st->sz;
957         sht.sh_type             = SHT_STRTAB;
958         sht.sh_flags            = 0;
959         sht.sh_entsize          = 0;
960         sht.sh_info             = 0;
961         sht.sh_link             = 0;
962
963         if (!gelf_update_shdr(sy->os, &shy))
964                 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
965                     elf_errmsg(-1));
966         if (!gelf_update_shdr(st->os, &sht))
967                 errx(EXIT_FAILURE, "gelf_update_shdr() failed: %s",
968                     elf_errmsg(-1));
969 }
970
971 void
972 add_to_symop_list(struct elfcopy *ecp, const char *name, const char *newname,
973     unsigned int op)
974 {
975         struct symop *s;
976
977         if ((s = lookup_symop_list(ecp, name, ~0U)) == NULL) {
978                 if ((s = calloc(1, sizeof(*s))) == NULL)
979                         errx(EXIT_FAILURE, "not enough memory");
980                 s->name = name;
981                 if (op == SYMOP_REDEF)
982                         s->newname = newname;
983         }
984
985         s->op |= op;
986         STAILQ_INSERT_TAIL(&ecp->v_symop, s, symop_list);
987 }
988
989 static int
990 match_wildcard(const char *name, const char *pattern)
991 {
992         int reverse, match;
993
994         reverse = 0;
995         if (*pattern == '!') {
996                 reverse = 1;
997                 pattern++;
998         }
999
1000         match = 0;
1001         if (!fnmatch(pattern, name, 0)) {
1002                 match = 1;
1003                 printf("string '%s' match to pattern '%s'\n", name, pattern);
1004         }
1005
1006         return (reverse ? !match : match);
1007 }
1008
1009 struct symop *
1010 lookup_symop_list(struct elfcopy *ecp, const char *name, unsigned int op)
1011 {
1012         struct symop *s;
1013
1014         STAILQ_FOREACH(s, &ecp->v_symop, symop_list) {
1015                 if (name == NULL || !strcmp(name, s->name) ||
1016                     ((ecp->flags & WILDCARD) && match_wildcard(name, s->name)))
1017                         if ((s->op & op) != 0)
1018                                 return (s);
1019         }
1020
1021         return (NULL);
1022 }
1023
1024 static int
1025 lookup_exact_string(const char *buf, size_t sz, const char *s)
1026 {
1027         const char      *b;
1028         size_t           slen;
1029
1030         slen = strlen(s);
1031         for (b = buf; b < buf + sz; b += strlen(b) + 1) {
1032                 if (strlen(b) != slen)
1033                         continue;
1034                 if (!strcmp(b, s))
1035                         return (b - buf);
1036         }
1037
1038         return (-1);
1039 }