]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/elftoolchain/nm/nm.c
Update to ELF Tool Chain r3475
[FreeBSD/FreeBSD.git] / contrib / elftoolchain / nm / nm.c
1 /*-
2  * Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com>
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  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include <sys/queue.h>
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <ar.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <dwarf.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <gelf.h>
38 #include <getopt.h>
39 #include <inttypes.h>
40 #include <libdwarf.h>
41 #include <libelftc.h>
42 #include <stdbool.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <strings.h>
47 #include <unistd.h>
48
49 #include "_elftc.h"
50
51 ELFTC_VCSID("$Id: nm.c 3472 2016-05-17 20:11:16Z emaste $");
52
53 /* symbol information list */
54 STAILQ_HEAD(sym_head, sym_entry);
55
56 struct sym_entry {
57         char            *name;
58         GElf_Sym        *sym;
59         STAILQ_ENTRY(sym_entry) sym_entries;
60 };
61
62 typedef int (*fn_sort)(const void *, const void *);
63 typedef void (*fn_elem_print)(char, const char *, const GElf_Sym *, const char *);
64 typedef void (*fn_sym_print)(const GElf_Sym *);
65 typedef int (*fn_filter)(char, const GElf_Sym *, const char *);
66
67 /* output filter list */
68 static SLIST_HEAD(filter_head, filter_entry) nm_out_filter =
69     SLIST_HEAD_INITIALIZER(nm_out_filter);
70
71 struct filter_entry {
72         fn_filter       fn;
73         SLIST_ENTRY(filter_entry) filter_entries;
74 };
75
76 struct sym_print_data {
77         struct sym_head *headp;
78         size_t          sh_num, list_num;
79         const char      *t_table, **s_table, *filename, *objname;
80 };
81
82 struct nm_prog_info {
83         const char      *name;
84         const char      *def_filename;
85 };
86
87 /* List for line number information. */
88 struct line_info_entry {
89         uint64_t        addr;   /* address */
90         uint64_t        line;   /* line number */
91         char            *file;  /* file name with path */
92         SLIST_ENTRY(line_info_entry) entries;
93 };
94 SLIST_HEAD(line_info_head, line_info_entry);
95
96 /* List for function line number information. */
97 struct func_info_entry {
98         char            *name;  /* function name */
99         char            *file;  /* file name with path */
100         uint64_t        lowpc;  /* low address */
101         uint64_t        highpc; /* high address */
102         uint64_t        line;   /* line number */
103         SLIST_ENTRY(func_info_entry) entries;
104 };
105 SLIST_HEAD(func_info_head, func_info_entry);
106
107 /* List for variable line number information. */
108 struct var_info_entry {
109         char            *name;  /* variable name */
110         char            *file;  /* file name with path */
111         uint64_t        addr;   /* address */
112         uint64_t        line;   /* line number */
113         SLIST_ENTRY(var_info_entry) entries;
114 };
115 SLIST_HEAD(var_info_head, var_info_entry);
116
117 /* output numric type */
118 enum radix {
119         RADIX_OCT,
120         RADIX_HEX,
121         RADIX_DEC
122 };
123
124 /* output symbol type, PRINT_SYM_DYN for dynamic symbol only */
125 enum print_symbol {
126         PRINT_SYM_SYM,
127         PRINT_SYM_DYN
128 };
129
130 /* output name type */
131 enum print_name {
132         PRINT_NAME_NONE,
133         PRINT_NAME_FULL,
134         PRINT_NAME_MULTI
135 };
136
137 struct nm_prog_options {
138         enum print_symbol       print_symbol;
139         enum print_name         print_name;
140         enum radix              t;
141         int                     demangle_type;
142         bool                    print_debug;
143         bool                    print_armap;
144         int                     print_size;
145         bool                    debug_line;
146         int                     def_only;
147         bool                    undef_only;
148         int                     sort_size;
149         bool                    sort_reverse;
150         int                     no_demangle;
151
152         /*
153          * function pointer to sort symbol list.
154          * possible function - cmp_name, cmp_none, cmp_size, cmp_value
155          */
156         fn_sort                 sort_fn;
157
158         /*
159          * function pointer to print symbol elem.
160          * possible function - sym_elem_print_all
161          *                     sym_elem_print_all_portable
162          *                     sym_elem_print_all_sysv
163          */
164         fn_elem_print           elem_print_fn;
165
166         fn_sym_print            value_print_fn;
167         fn_sym_print            size_print_fn;
168 };
169
170 #define CHECK_SYM_PRINT_DATA(p) (p->headp == NULL || p->sh_num == 0 ||        \
171 p->t_table == NULL || p->s_table == NULL || p->filename == NULL)
172 #define IS_SYM_TYPE(t)          ((t) == '?' || isalpha((t)) != 0)
173 #define IS_UNDEF_SYM_TYPE(t)    ((t) == 'U' || (t) == 'v' || (t) == 'w')
174 #define UNUSED(p)               ((void)p)
175
176 static int              cmp_name(const void *, const void *);
177 static int              cmp_none(const void *, const void *);
178 static int              cmp_size(const void *, const void *);
179 static int              cmp_value(const void *, const void *);
180 static void             filter_dest(void);
181 static int              filter_insert(fn_filter);
182 static void             get_opt(int, char **);
183 static int              get_sym(Elf *, struct sym_head *, int, size_t, size_t,
184                             const char *, const char **, int);
185 static const char *     get_sym_name(Elf *, const GElf_Sym *, size_t,
186                             const char **, int);
187 static char             get_sym_type(const GElf_Sym *, const char *);
188 static void             global_dest(void);
189 static void             global_init(void);
190 static bool             is_sec_data(GElf_Shdr *);
191 static bool             is_sec_debug(const char *);
192 static bool             is_sec_nobits(GElf_Shdr *);
193 static bool             is_sec_readonly(GElf_Shdr *);
194 static bool             is_sec_text(GElf_Shdr *);
195 static void             print_ar_index(int, Elf *);
196 static void             print_header(const char *, const char *);
197 static void             print_version(void);
198 static int              read_elf(Elf *, const char *, Elf_Kind);
199 static int              read_object(const char *);
200 static int              read_files(int, char **);
201 static void             set_opt_value_print_fn(enum radix);
202 static int              sym_elem_def(char, const GElf_Sym *, const char *);
203 static int              sym_elem_global(char, const GElf_Sym *, const char *);
204 static int              sym_elem_global_static(char, const GElf_Sym *,
205                             const char *);
206 static int              sym_elem_nondebug(char, const GElf_Sym *, const char *);
207 static int              sym_elem_nonzero_size(char, const GElf_Sym *,
208                             const char *);
209 static void             sym_elem_print_all(char, const char *,
210                             const GElf_Sym *, const char *);
211 static void             sym_elem_print_all_portable(char, const char *,
212                             const GElf_Sym *, const char *);
213 static void             sym_elem_print_all_sysv(char, const char *,
214                             const GElf_Sym *, const char *);
215 static int              sym_elem_undef(char, const GElf_Sym *, const char *);
216 static void             sym_list_dest(struct sym_head *);
217 static int              sym_list_insert(struct sym_head *, const char *,
218                             const GElf_Sym *);
219 static void             sym_list_print(struct sym_print_data *,
220                             struct func_info_head *, struct var_info_head *,
221                             struct line_info_head *);
222 static void             sym_list_print_each(struct sym_entry *,
223                             struct sym_print_data *, struct func_info_head *,
224                             struct var_info_head *, struct line_info_head *);
225 static struct sym_entry *sym_list_sort(struct sym_print_data *);
226 static void             sym_size_oct_print(const GElf_Sym *);
227 static void             sym_size_hex_print(const GElf_Sym *);
228 static void             sym_size_dec_print(const GElf_Sym *);
229 static void             sym_value_oct_print(const GElf_Sym *);
230 static void             sym_value_hex_print(const GElf_Sym *);
231 static void             sym_value_dec_print(const GElf_Sym *);
232 static void             usage(int);
233
234 static struct nm_prog_info      nm_info;
235 static struct nm_prog_options   nm_opts;
236 static int                      nm_elfclass;
237
238 /*
239  * Point to current sym_print_data to use portable qsort function.
240  *  (e.g. There is no qsort_r function in NetBSD.)
241  *
242  * Using in sym_list_sort.
243  */
244 static struct sym_print_data    *nm_print_data;
245
246 static const struct option nm_longopts[] = {
247         { "debug-syms",         no_argument,            NULL,           'a' },
248         { "defined-only",       no_argument,            &nm_opts.def_only, 1},
249         { "demangle",           optional_argument,      NULL,           'C' },
250         { "dynamic",            no_argument,            NULL,           'D' },
251         { "extern-only",        no_argument,            NULL,           'g' },
252         { "format",             required_argument,      NULL,           'F' },
253         { "help",               no_argument,            NULL,           'h' },
254         { "line-numbers",       no_argument,            NULL,           'l' },
255         { "no-demangle",        no_argument,            &nm_opts.no_demangle,
256           1},
257         { "no-sort",            no_argument,            NULL,           'p' },
258         { "numeric-sort",       no_argument,            NULL,           'v' },
259         { "print-armap",        no_argument,            NULL,           's' },
260         { "print-file-name",    no_argument,            NULL,           'A' },
261         { "print-size",         no_argument,            NULL,           'S' },
262         { "radix",              required_argument,      NULL,           't' },
263         { "reverse-sort",       no_argument,            NULL,           'r' },
264         { "size-sort",          no_argument,            &nm_opts.sort_size, 1},
265         { "undefined-only",     no_argument,            NULL,           'u' },
266         { "version",            no_argument,            NULL,           'V' },
267         { NULL,                 0,                      NULL,           0   }
268 };
269
270 #if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS)
271 static __inline uint32_t
272 be32dec(const void *pp)
273 {
274         unsigned char const *p = (unsigned char const *)pp;
275
276         return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
277 }
278
279 static __inline uint32_t
280 le32dec(const void *pp)
281 {
282         unsigned char const *p = (unsigned char const *)pp;
283
284         return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
285 }
286
287 static __inline uint64_t
288 be64dec(const void *pp)
289 {
290         unsigned char const *p = (unsigned char const *)pp;
291
292         return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
293 }
294
295 static __inline uint64_t
296 le64dec(const void *pp)
297 {
298         unsigned char const *p = (unsigned char const *)pp;
299
300         return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
301 }
302 #endif
303
304 static int
305 cmp_name(const void *l, const void *r)
306 {
307
308         assert(l != NULL);
309         assert(r != NULL);
310         assert(((const struct sym_entry *)l)->name != NULL);
311         assert(((const struct sym_entry *)r)->name != NULL);
312
313         return (strcmp(((const struct sym_entry *)l)->name,
314             ((const struct sym_entry *)r)->name));
315 }
316
317 static int
318 cmp_none(const void *l, const void *r)
319 {
320
321         UNUSED(l);
322         UNUSED(r);
323
324         return (0);
325 }
326
327 /* Size comparison. If l and r have same size, compare their name. */
328 static int
329 cmp_size(const void *lp, const void *rp)
330 {
331         const struct sym_entry *l, *r;
332
333         l = lp;
334         r = rp;
335
336         assert(l != NULL);
337         assert(l->name != NULL);
338         assert(l->sym != NULL);
339         assert(r != NULL);
340         assert(r->name != NULL);
341         assert(r->sym != NULL);
342
343         if (l->sym->st_size == r->sym->st_size)
344                 return (strcmp(l->name, r->name));
345
346         return (l->sym->st_size - r->sym->st_size);
347 }
348
349 /* Value comparison. Undefined symbols come first. */
350 static int
351 cmp_value(const void *lp, const void *rp)
352 {
353         const struct sym_entry *l, *r;
354         const char *ttable;
355         int l_is_undef, r_is_undef;
356
357         l = lp;
358         r = rp;
359
360         assert(nm_print_data != NULL);
361         ttable = nm_print_data->t_table;
362
363         assert(l != NULL);
364         assert(l->name != NULL);
365         assert(l->sym != NULL);
366         assert(r != NULL);
367         assert(r->name != NULL);
368         assert(r->sym != NULL);
369         assert(ttable != NULL);
370
371         l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0;
372         r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0;
373
374         assert(l_is_undef + r_is_undef >= 0);
375         assert(l_is_undef + r_is_undef <= 2);
376
377         switch (l_is_undef + r_is_undef) {
378         case 0:
379                 /* Both defined */
380                 if (l->sym->st_value == r->sym->st_value)
381                         return (strcmp(l->name, r->name));
382                 return (l->sym->st_value > r->sym->st_value ? 1 : -1);
383         case 1:
384                 /* One undefined */
385                 return (l_is_undef == 0 ? 1 : -1);
386         case 2:
387                 /* Both undefined */
388                 return (strcmp(l->name, r->name));
389         }
390         /* NOTREACHED */
391
392         return (l->sym->st_value - r->sym->st_value);
393 }
394
395 static void
396 filter_dest(void)
397 {
398         struct filter_entry *e;
399
400         while (!SLIST_EMPTY(&nm_out_filter)) {
401                 e = SLIST_FIRST(&nm_out_filter);
402                 SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries);
403                 free(e);
404         }
405 }
406
407 static int
408 filter_insert(fn_filter filter_fn)
409 {
410         struct filter_entry *e;
411
412         assert(filter_fn != NULL);
413
414         if ((e = malloc(sizeof(struct filter_entry))) == NULL) {
415                 warn("malloc");
416                 return (0);
417         }
418         e->fn = filter_fn;
419         SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries);
420
421         return (1);
422 }
423
424 static int
425 parse_demangle_option(const char *opt)
426 {
427
428         if (opt == NULL)
429                 return (ELFTC_DEM_UNKNOWN);
430         else if (!strncasecmp(opt, "gnu-v2", 6))
431                 return (ELFTC_DEM_GNU2);
432         else if (!strncasecmp(opt, "gnu-v3", 6))
433                 return (ELFTC_DEM_GNU3);
434         else if (!strncasecmp(opt, "arm", 3))
435                 return (ELFTC_DEM_ARM);
436         else
437                 errx(EXIT_FAILURE, "unknown demangling style '%s'", opt);
438
439         /* NOTREACHED */
440         return (0);
441 }
442
443 static void
444 get_opt(int argc, char **argv)
445 {
446         int ch;
447         bool is_posix, oflag;
448
449         if (argc <= 0 || argv == NULL)
450                 return;
451
452         oflag = is_posix = false;
453         nm_opts.t = RADIX_HEX;
454         while ((ch = getopt_long(argc, argv, "ABCDF:PSVaefghlnoprst:uvx",
455                     nm_longopts, NULL)) != -1) {
456                 switch (ch) {
457                 case 'A':
458                         nm_opts.print_name = PRINT_NAME_FULL;
459                         break;
460                 case 'B':
461                         nm_opts.elem_print_fn = &sym_elem_print_all;
462                         break;
463                 case 'C':
464                         nm_opts.demangle_type = parse_demangle_option(optarg);
465                         break;
466                 case 'D':
467                         nm_opts.print_symbol = PRINT_SYM_DYN;
468                         break;
469                 case 'F':
470                         /* sysv, bsd, posix */
471                         switch (optarg[0]) {
472                         case 'B':
473                         case 'b':
474                                 nm_opts.elem_print_fn = &sym_elem_print_all;
475                                 break;
476                         case 'P':
477                         case 'p':
478                                 is_posix = true;
479                                 nm_opts.elem_print_fn =
480                                     &sym_elem_print_all_portable;
481                                 break;
482                         case 'S':
483                         case 's':
484                                 nm_opts.elem_print_fn =
485                                     &sym_elem_print_all_sysv;
486                                 break;
487                         default:
488                                 warnx("%s: Invalid format", optarg);
489                                 usage(1);
490                         }
491
492                         break;
493                 case 'P':
494                         is_posix = true;
495                         nm_opts.elem_print_fn = &sym_elem_print_all_portable;
496                         break;
497                 case 'S':
498                         nm_opts.print_size = 1;
499                         break;
500                 case 'V':
501                         print_version();
502                         /* NOTREACHED */
503                 case 'a':
504                         nm_opts.print_debug = true;
505                         break;
506                 case 'e':
507                         filter_insert(sym_elem_global_static);
508                         break;
509                 case 'f':
510                         break;
511                 case 'g':
512                         filter_insert(sym_elem_global);
513                         break;
514                 case 'h':
515                         usage(0);
516                         break;
517                 case 'l':
518                         nm_opts.debug_line = true;
519                         break;
520                 case 'n':
521                 case 'v':
522                         nm_opts.sort_fn = &cmp_value;
523                         break;
524                 case 'o':
525                         oflag = true;
526                         break;
527                 case 'p':
528                         nm_opts.sort_fn = &cmp_none;
529                         break;
530                 case 'r':
531                         nm_opts.sort_reverse = true;
532                         break;
533                 case 's':
534                         nm_opts.print_armap = true;
535                         break;
536                 case 't':
537                         /* t require always argument to getopt_long */
538                         switch (optarg[0]) {
539                         case 'd':
540                                 nm_opts.t = RADIX_DEC;
541                                 break;
542                         case 'o':
543                                 nm_opts.t = RADIX_OCT;
544                                 break;
545                         case 'x':
546                                 nm_opts.t = RADIX_HEX;
547                                 break;
548                         default:
549                                 warnx("%s: Invalid radix", optarg);
550                                 usage(1);
551                         }
552                         break;
553                 case 'u':
554                         filter_insert(sym_elem_undef);
555                         nm_opts.undef_only = true;
556                         break;
557                 /* case 'v': see case 'n' above. */
558                 case 'x':
559                         nm_opts.t = RADIX_HEX;
560                         break;
561                 case 0:
562                         if (nm_opts.sort_size != 0) {
563                                 nm_opts.sort_fn = &cmp_size;
564                                 filter_insert(sym_elem_def);
565                                 filter_insert(sym_elem_nonzero_size);
566                         }
567                         if (nm_opts.def_only != 0)
568                                 filter_insert(sym_elem_def);
569                         if (nm_opts.no_demangle != 0)
570                                 nm_opts.demangle_type = -1;
571                         break;
572                 default :
573                         usage(1);
574                 }
575         }
576
577         /*
578          * In POSIX mode, the '-o' option controls the output radix.
579          * In non-POSIX mode, the option is a synonym for the '-A' and
580          * '--print-file-name' options.
581          */
582         if (oflag) {
583                 if (is_posix)
584                         nm_opts.t = RADIX_OCT;
585                 else
586                         nm_opts.print_name = PRINT_NAME_FULL;
587         }
588
589         assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null");
590         assert(nm_opts.elem_print_fn != NULL &&
591             "nm_opts.elem_print_fn is null");
592         assert(nm_opts.value_print_fn != NULL &&
593             "nm_opts.value_print_fn is null");
594
595         set_opt_value_print_fn(nm_opts.t);
596
597         if (nm_opts.undef_only == true) {
598                 if (nm_opts.sort_fn == &cmp_size)
599                         errx(EXIT_FAILURE,
600                             "--size-sort with -u is meaningless");
601                 if (nm_opts.def_only != 0)
602                         errx(EXIT_FAILURE,
603                             "-u with --defined-only is meaningless");
604         }
605         if (nm_opts.print_debug == false)
606                 filter_insert(sym_elem_nondebug);
607         if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none)
608                 nm_opts.sort_reverse = false;
609 }
610
611 /*
612  * Get symbol information from elf.
613  */
614 static int
615 get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx,
616     size_t strndx, const char *type_table, const char **sec_table,
617     int sec_table_size)
618 {
619         Elf_Scn *scn;
620         Elf_Data *data;
621         GElf_Shdr shdr;
622         GElf_Sym sym;
623         struct filter_entry *fep;
624         size_t ndx;
625         int rtn;
626         const char *sym_name;
627         char type;
628         bool filter;
629         int i, j;
630
631         assert(elf != NULL);
632         assert(headp != NULL);
633
634         rtn = 0;
635         for (i = 1; i < shnum; i++) {
636                 if ((scn = elf_getscn(elf, i)) == NULL) {
637                         warnx("elf_getscn failed: %s", elf_errmsg(-1));
638                         continue;
639                 }
640                 if (gelf_getshdr(scn, &shdr) != &shdr) {
641                         warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
642                         continue;
643                 }
644                 if (shdr.sh_type == SHT_SYMTAB) {
645                         if (nm_opts.print_symbol != PRINT_SYM_SYM)
646                                 continue;
647                 } else if (shdr.sh_type == SHT_DYNSYM) {
648                         if (nm_opts.print_symbol != PRINT_SYM_DYN)
649                                 continue;
650                 } else
651                         continue;
652
653                 ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx;
654
655                 data = NULL;
656                 while ((data = elf_getdata(scn, data)) != NULL) {
657                         j = 1;
658                         while (gelf_getsym(data, j++, &sym) != NULL) {
659                                 sym_name = get_sym_name(elf, &sym, ndx,
660                                     sec_table, sec_table_size);
661                                 filter = false;
662                                 type = get_sym_type(&sym, type_table);
663                                 SLIST_FOREACH(fep, &nm_out_filter,
664                                     filter_entries) {
665                                         if (!fep->fn(type, &sym, sym_name)) {
666                                                 filter = true;
667                                                 break;
668                                         }
669                                 }
670                                 if (filter == false) {
671                                         if (sym_list_insert(headp, sym_name,
672                                             &sym) == 0)
673                                                 return (0);
674                                         rtn++;
675                                 }
676                         }
677                 }
678         }
679
680         return (rtn);
681 }
682
683 static const char *
684 get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table,
685     int sec_table_size)
686 {
687         const char *sym_name;
688
689         sym_name = NULL;
690
691         /* Show section name as symbol name for STT_SECTION symbols. */
692         if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) {
693                 if (sec_table != NULL && sym->st_shndx < sec_table_size)
694                         sym_name = sec_table[sym->st_shndx];
695         } else
696                 sym_name = elf_strptr(elf, ndx, sym->st_name);
697
698         if (sym_name == NULL)
699                 sym_name = "(null)";
700
701         return (sym_name);
702 }
703
704 static char
705 get_sym_type(const GElf_Sym *sym, const char *type_table)
706 {
707         bool is_local;
708
709         if (sym == NULL || type_table == NULL)
710                 return ('?');
711
712         is_local = sym->st_info >> 4 == STB_LOCAL;
713
714         if (sym->st_shndx == SHN_ABS) /* absolute */
715                 return (is_local ? 'a' : 'A');
716
717         if (sym->st_shndx == SHN_COMMON) /* common */
718                 return ('C');
719
720         if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */
721                 if ((sym->st_info & 0xf) == STT_OBJECT)
722                         return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V');
723
724                 return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W');
725         }
726
727         if (sym->st_shndx == SHN_UNDEF) /* undefined */
728                 return ('U');
729
730         return (is_local == true && type_table[sym->st_shndx] != 'N' ?
731             tolower((unsigned char) type_table[sym->st_shndx]) :
732             type_table[sym->st_shndx]);
733 }
734
735 static void
736 global_dest(void)
737 {
738
739         filter_dest();
740 }
741
742 static void
743 global_init(void)
744 {
745
746         if (elf_version(EV_CURRENT) == EV_NONE)
747                 errx(EXIT_FAILURE, "elf_version error");
748
749         nm_info.name = ELFTC_GETPROGNAME();
750         nm_info.def_filename = "a.out";
751         nm_opts.print_symbol = PRINT_SYM_SYM;
752         nm_opts.print_name = PRINT_NAME_NONE;
753         nm_opts.demangle_type = -1;
754         nm_opts.print_debug = false;
755         nm_opts.print_armap = false;
756         nm_opts.print_size = 0;
757         nm_opts.debug_line = false;
758         nm_opts.def_only = 0;
759         nm_opts.undef_only = false;
760         nm_opts.sort_size = 0;
761         nm_opts.sort_reverse = false;
762         nm_opts.no_demangle = 0;
763         nm_opts.sort_fn = &cmp_name;
764         nm_opts.elem_print_fn = &sym_elem_print_all;
765         nm_opts.value_print_fn = &sym_value_dec_print;
766         nm_opts.size_print_fn = &sym_size_dec_print;
767         SLIST_INIT(&nm_out_filter);
768 }
769
770 static bool
771 is_sec_data(GElf_Shdr *s)
772 {
773
774         assert(s != NULL && "shdr is NULL");
775
776         return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS);
777 }
778
779 static bool
780 is_sec_debug(const char *shname)
781 {
782         const char *dbg_sec[] = {
783                 ".debug",
784                 ".gnu.linkonce.wi.",
785                 ".line",
786                 ".rel.debug",
787                 ".rela.debug",
788                 ".stab",
789                 NULL
790         };
791         const char **p;
792
793         if (shname == NULL)
794                 return (false);
795
796         for (p = dbg_sec; *p; p++) {
797                 if (!strncmp(shname, *p, strlen(*p)))
798                         return (true);
799         }
800
801         return (false);
802 }
803
804 static bool
805 is_sec_nobits(GElf_Shdr *s)
806 {
807
808         assert(s != NULL && "shdr is NULL");
809
810         return (s->sh_type == SHT_NOBITS);
811 }
812
813 static bool
814 is_sec_readonly(GElf_Shdr *s)
815 {
816
817         assert(s != NULL && "shdr is NULL");
818
819         return ((s->sh_flags & SHF_WRITE) == 0);
820 }
821
822 static bool
823 is_sec_text(GElf_Shdr *s)
824 {
825
826         assert(s != NULL && "shdr is NULL");
827
828         return ((s->sh_flags & SHF_EXECINSTR) != 0);
829 }
830
831 static void
832 print_ar_index(int fd, Elf *arf)
833 {
834         Elf *elf;
835         Elf_Arhdr *arhdr;
836         Elf_Arsym *arsym;
837         Elf_Cmd cmd;
838         off_t start;
839         size_t arsym_size;
840
841         if (arf == NULL)
842                 return;
843
844         if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL)
845                 return;
846
847         printf("\nArchive index:\n");
848
849         start = arsym->as_off;
850         cmd = ELF_C_READ;
851         while (arsym_size > 1) {
852                 if (elf_rand(arf, arsym->as_off) == arsym->as_off &&
853                     (elf = elf_begin(fd, cmd, arf)) != NULL) {
854                         if ((arhdr = elf_getarhdr(elf)) != NULL)
855                                 printf("%s in %s\n", arsym->as_name,
856                                     arhdr->ar_name != NULL ?
857                                     arhdr->ar_name : arhdr->ar_rawname);
858                         elf_end(elf);
859                 }
860                 ++arsym;
861                 --arsym_size;
862         }
863
864         elf_rand(arf, start);
865 }
866
867 #define DEMANGLED_BUFFER_SIZE   (8 * 1024)
868 #define PRINT_DEMANGLED_NAME(FORMAT, NAME) do {                         \
869         char _demangled[DEMANGLED_BUFFER_SIZE];                         \
870         if (nm_opts.demangle_type < 0 ||                                \
871             elftc_demangle((NAME), _demangled, sizeof(_demangled),      \
872                 nm_opts.demangle_type) < 0)                             \
873                 printf((FORMAT), (NAME));                               \
874         else                                                            \
875                 printf((FORMAT), _demangled);                           \
876         } while (0)
877
878 static void
879 print_header(const char *file, const char *obj)
880 {
881
882         if (file == NULL)
883                 return;
884
885         if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) {
886                 printf("\n\n%s from %s",
887                     nm_opts.undef_only == false ? "Symbols" :
888                     "Undefined symbols", file);
889                 if (obj != NULL)
890                         printf("[%s]", obj);
891                 printf(":\n\n");
892
893                 printf("\
894 Name                  Value           Class        Type         Size             Line  Section\n\n");
895         } else {
896                 /* archive file without -A option and POSIX */
897                 if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) {
898                         if (nm_opts.elem_print_fn ==
899                             sym_elem_print_all_portable)
900                                 printf("%s[%s]:\n", file, obj);
901                         else if (nm_opts.elem_print_fn == sym_elem_print_all)
902                                 printf("\n%s:\n", obj);
903                         /* multiple files(not archive) without -A option */
904                 } else if (nm_opts.print_name == PRINT_NAME_MULTI) {
905                         if (nm_opts.elem_print_fn == sym_elem_print_all)
906                                 printf("\n");
907                         printf("%s:\n", file);
908                 }
909         }
910 }
911
912 static void
913 print_version(void)
914 {
915
916         (void) printf("%s (%s)\n", nm_info.name, elftc_version());
917         exit(0);
918 }
919
920 static uint64_t
921 get_block_value(Dwarf_Debug dbg, Dwarf_Block *block)
922 {
923         Elf *elf;
924         GElf_Ehdr eh;
925         Dwarf_Error de;
926
927         if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) {
928                 warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de));
929                 return (0);
930         }
931
932         if (gelf_getehdr(elf, &eh) != &eh) {
933                 warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
934                 return (0);
935         }
936
937         if (block->bl_len == 5) {
938                 if (eh.e_ident[EI_DATA] == ELFDATA2LSB)
939                         return (le32dec((uint8_t *) block->bl_data + 1));
940                 else
941                         return (be32dec((uint8_t *) block->bl_data + 1));
942         } else if (block->bl_len == 9) {
943                 if (eh.e_ident[EI_DATA] == ELFDATA2LSB)
944                         return (le64dec((uint8_t *) block->bl_data + 1));
945                 else
946                         return (be64dec((uint8_t *) block->bl_data + 1));
947         }
948
949         return (0);
950 }
951
952 static char *
953 find_object_name(Dwarf_Debug dbg, Dwarf_Die die)
954 {
955         Dwarf_Die ret_die;
956         Dwarf_Attribute at;
957         Dwarf_Off off;
958         Dwarf_Error de;
959         const char *str;
960         char *name;
961
962         if (dwarf_attrval_string(die, DW_AT_name, &str, &de) == DW_DLV_OK) {
963                 if ((name = strdup(str)) == NULL) {
964                         warn("strdup");
965                         return (NULL);
966                 }
967                 return (name);
968         }
969
970         if (dwarf_attr(die, DW_AT_specification, &at, &de) != DW_DLV_OK)
971                 return (NULL);
972
973         if (dwarf_global_formref(at, &off, &de) != DW_DLV_OK)
974                 return (NULL);
975
976         if (dwarf_offdie(dbg, off, &ret_die, &de) != DW_DLV_OK)
977                 return (NULL);
978
979         return (find_object_name(dbg, ret_die));
980 }
981
982 static void
983 search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info,
984     struct var_info_head *var_info, Dwarf_Die die, char **src_files,
985     Dwarf_Signed filecount)
986 {
987         Dwarf_Attribute at;
988         Dwarf_Unsigned udata;
989         Dwarf_Half tag;
990         Dwarf_Block *block;
991         Dwarf_Bool flag;
992         Dwarf_Die ret_die;
993         Dwarf_Error de;
994         struct func_info_entry *func;
995         struct var_info_entry *var;
996         int ret;
997
998         if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
999                 warnx("dwarf_tag failed: %s", dwarf_errmsg(de));
1000                 goto cont_search;
1001         }
1002
1003         /* We're interested in DIEs which define functions or variables. */
1004         if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point &&
1005             tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable)
1006                 goto cont_search;
1007
1008         if (tag == DW_TAG_variable) {
1009
1010                 /* Ignore "artificial" variable. */
1011                 if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) ==
1012                     DW_DLV_OK && flag)
1013                         goto cont_search;
1014
1015                 /* Ignore pure declaration. */
1016                 if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) ==
1017                     DW_DLV_OK && flag)
1018                         goto cont_search;
1019
1020                 /* Ignore stack varaibles. */
1021                 if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) !=
1022                     DW_DLV_OK || !flag)
1023                         goto cont_search;
1024
1025                 if ((var = calloc(1, sizeof(*var))) == NULL) {
1026                         warn("calloc failed");
1027                         goto cont_search;
1028                 }
1029
1030                 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata,
1031                     &de) == DW_DLV_OK && udata > 0 &&
1032                     (Dwarf_Signed) (udata - 1) < filecount) {
1033                         var->file = strdup(src_files[udata - 1]);
1034                         if (var->file == NULL) {
1035                                 warn("strdup");
1036                                 free(var);
1037                                 goto cont_search;
1038                         }
1039                 }
1040
1041                 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) ==
1042                     DW_DLV_OK)
1043                         var->line = udata;
1044
1045                 var->name = find_object_name(dbg, die);
1046                 if (var->name == NULL) {
1047                         if (var->file)
1048                                 free(var->file);
1049                         free(var);
1050                         goto cont_search;
1051                 }
1052
1053                 if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK &&
1054                     dwarf_formblock(at, &block, &de) == DW_DLV_OK) {
1055                         /*
1056                          * Since we ignored stack variables, the rest are the
1057                          * external varaibles which should always use DW_OP_addr
1058                          * operator for DW_AT_location value.
1059                          */
1060                         if (*((uint8_t *)block->bl_data) == DW_OP_addr)
1061                                 var->addr = get_block_value(dbg, block);
1062                 }
1063
1064                 SLIST_INSERT_HEAD(var_info, var, entries);
1065
1066         } else {
1067
1068                 if ((func = calloc(1, sizeof(*func))) == NULL) {
1069                         warn("calloc failed");
1070                         goto cont_search;
1071                 }
1072
1073                 /*
1074                  * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin
1075                  * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line
1076                  * attributes for inlined functions as well.
1077                  */
1078                 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata,
1079                     &de) == DW_DLV_OK && udata > 0 &&
1080                     (Dwarf_Signed) (udata - 1) < filecount) {
1081                         func->file = strdup(src_files[udata - 1]);
1082                         if (func->file == NULL) {
1083                                 warn("strdup");
1084                                 free(func);
1085                                 goto cont_search;
1086                         }
1087                 }
1088
1089                 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) ==
1090                     DW_DLV_OK)
1091                         func->line = udata;
1092
1093                 func->name = find_object_name(dbg, die);
1094                 if (func->name == NULL) {
1095                         if (func->file)
1096                                 free(func->file);
1097                         free(func);
1098                         goto cont_search;
1099                 }
1100
1101                 if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) ==
1102                     DW_DLV_OK)
1103                         func->lowpc = udata;
1104                 if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) ==
1105                     DW_DLV_OK)
1106                         func->highpc = udata;
1107
1108                 SLIST_INSERT_HEAD(func_info, func, entries);
1109         }
1110
1111 cont_search:
1112
1113         /* Search children. */
1114         ret = dwarf_child(die, &ret_die, &de);
1115         if (ret == DW_DLV_ERROR)
1116                 warnx("dwarf_child: %s", dwarf_errmsg(de));
1117         else if (ret == DW_DLV_OK)
1118                 search_line_attr(dbg, func_info, var_info, ret_die, src_files,
1119                     filecount);
1120
1121         /* Search sibling. */
1122         ret = dwarf_siblingof(dbg, die, &ret_die, &de);
1123         if (ret == DW_DLV_ERROR)
1124                 warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
1125         else if (ret == DW_DLV_OK)
1126                 search_line_attr(dbg, func_info, var_info, ret_die, src_files,
1127                     filecount);
1128
1129         dwarf_dealloc(dbg, die, DW_DLA_DIE);
1130 }
1131
1132 /*
1133  * Read elf file and collect symbol information, sort them, print.
1134  * Return 1 at failed, 0 at success.
1135  */
1136 static int
1137 read_elf(Elf *elf, const char *filename, Elf_Kind kind)
1138 {
1139         Dwarf_Debug dbg;
1140         Dwarf_Die die;
1141         Dwarf_Error de;
1142         Dwarf_Half tag;
1143         Elf_Arhdr *arhdr;
1144         Elf_Scn *scn;
1145         GElf_Shdr shdr;
1146         GElf_Half i;
1147         Dwarf_Line *lbuf;
1148         Dwarf_Unsigned lineno;
1149         Dwarf_Signed lcount, filecount;
1150         Dwarf_Addr lineaddr;
1151         struct sym_print_data p_data;
1152         struct sym_head list_head;
1153         struct line_info_head *line_info;
1154         struct func_info_head *func_info;
1155         struct var_info_head *var_info;
1156         struct line_info_entry *lie;
1157         struct func_info_entry *func;
1158         struct var_info_entry *var;
1159         const char *shname, *objname;
1160         char *type_table, **sec_table, *sfile, **src_files;
1161         size_t shstrndx, shnum, dynndx, strndx;
1162         int ret, rtn, e_err;
1163
1164 #define OBJNAME (objname == NULL ? filename : objname)
1165
1166         assert(filename != NULL && "filename is null");
1167
1168         STAILQ_INIT(&list_head);
1169         type_table = NULL;
1170         sec_table = NULL;
1171         line_info = NULL;
1172         func_info = NULL;
1173         var_info = NULL;
1174         objname = NULL;
1175         dynndx = SHN_UNDEF;
1176         strndx = SHN_UNDEF;
1177         rtn = 0;
1178
1179         nm_elfclass = gelf_getclass(elf);
1180
1181         if (kind == ELF_K_AR) {
1182                 if ((arhdr = elf_getarhdr(elf)) == NULL)
1183                         goto next_cmd;
1184                 objname = arhdr->ar_name != NULL ? arhdr->ar_name :
1185                     arhdr->ar_rawname;
1186         }
1187         if (!elf_getshnum(elf, &shnum)) {
1188                 if ((e_err = elf_errno()) != 0)
1189                         warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1190                 else
1191                         warnx("%s: cannot get section number", OBJNAME);
1192                 rtn = 1;
1193                 goto next_cmd;
1194         }
1195         if (shnum == 0) {
1196                 warnx("%s: has no section", OBJNAME);
1197                 rtn = 1;
1198                 goto next_cmd;
1199         }
1200         if (!elf_getshstrndx(elf, &shstrndx)) {
1201                 warnx("%s: cannot get str index", OBJNAME);
1202                 rtn = 1;
1203                 goto next_cmd;
1204         }
1205         /* type_table for type determine */
1206         if ((type_table = malloc(sizeof(char) * shnum)) == NULL) {
1207                 warn("%s: malloc", OBJNAME);
1208                 rtn = 1;
1209                 goto next_cmd;
1210         }
1211         /* sec_table for section name to display in sysv format */
1212         if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) {
1213                 warn("%s: calloc", OBJNAME);
1214                 rtn = 1;
1215                 goto next_cmd;
1216         }
1217
1218         type_table[0] = 'U';
1219         if ((sec_table[0] = strdup("*UND*")) == NULL) {
1220                 warn("strdup");
1221                 goto next_cmd;
1222         }
1223
1224         for (i = 1; i < shnum; ++i) {
1225                 type_table[i] = 'U';
1226                 if ((scn = elf_getscn(elf, i)) == NULL) {
1227                         if ((e_err = elf_errno()) != 0)
1228                                 warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1229                         else
1230                                 warnx("%s: cannot get section", OBJNAME);
1231                         rtn = 1;
1232                         goto next_cmd;
1233                 }
1234                 if (gelf_getshdr(scn, &shdr) == NULL)
1235                         goto next_cmd;
1236
1237                 /*
1238                  * Cannot test by type and attribute for dynstr, strtab
1239                  */
1240                 shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name);
1241                 if (shname != NULL) {
1242                         if ((sec_table[i] = strdup(shname)) == NULL) {
1243                                 warn("strdup");
1244                                 goto next_cmd;
1245                         }
1246                         if (!strncmp(shname, ".dynstr", 7)) {
1247                                 dynndx = elf_ndxscn(scn);
1248                                 if (dynndx == SHN_UNDEF) {
1249                                         warnx("%s: elf_ndxscn failed: %s",
1250                                             OBJNAME, elf_errmsg(-1));
1251                                         goto next_cmd;
1252                                 }
1253                         }
1254                         if (!strncmp(shname, ".strtab", 7)) {
1255                                 strndx = elf_ndxscn(scn);
1256                                 if (strndx == SHN_UNDEF) {
1257                                         warnx("%s: elf_ndxscn failed: %s",
1258                                             OBJNAME, elf_errmsg(-1));
1259                                         goto next_cmd;
1260                                 }                                       
1261                         }
1262                 } else {
1263                         sec_table[i] = strdup("*UND*");
1264                         if (sec_table[i] == NULL) {
1265                                 warn("strdup");
1266                                 goto next_cmd;
1267                         }
1268                 }
1269
1270
1271                 if (is_sec_text(&shdr))
1272                         type_table[i] = 'T';
1273                 else if (is_sec_data(&shdr)) {
1274                         if (is_sec_readonly(&shdr))
1275                                 type_table[i] = 'R';
1276                         else
1277                                 type_table[i] = 'D';
1278                 } else if (is_sec_nobits(&shdr))
1279                         type_table[i] = 'B';
1280                 else if (is_sec_debug(shname))
1281                         type_table[i] = 'N';
1282                 else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr))
1283                         type_table[i] = 'n';
1284         }
1285
1286         print_header(filename, objname);
1287
1288         if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) ||
1289             (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) {
1290                 warnx("%s: no symbols", OBJNAME);
1291                 /* This is not an error case */
1292                 goto next_cmd;
1293         }
1294
1295         STAILQ_INIT(&list_head);
1296
1297         if (!nm_opts.debug_line)
1298                 goto process_sym;
1299
1300         /*
1301          * Collect dwarf line number information.
1302          */
1303
1304         if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) !=
1305             DW_DLV_OK) {
1306                 warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de));
1307                 goto process_sym;
1308         }
1309
1310         line_info = malloc(sizeof(struct line_info_head));
1311         func_info = malloc(sizeof(struct func_info_head));
1312         var_info = malloc(sizeof(struct var_info_head));
1313         if (line_info == NULL || func_info == NULL || var_info == NULL) {
1314                 warn("malloc");
1315                 (void) dwarf_finish(dbg, &de);
1316                 goto process_sym;
1317         }
1318         SLIST_INIT(line_info);
1319         SLIST_INIT(func_info);
1320         SLIST_INIT(var_info);
1321
1322         while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
1323             &de)) ==  DW_DLV_OK) {
1324                 die = NULL;
1325                 while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
1326                         if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
1327                                 warnx("dwarf_tag failed: %s",
1328                                     dwarf_errmsg(de));
1329                                 continue;
1330                         }
1331                         /* XXX: What about DW_TAG_partial_unit? */
1332                         if (tag == DW_TAG_compile_unit)
1333                                 break;
1334                 }
1335                 if (die == NULL) {
1336                         warnx("could not find DW_TAG_compile_unit die");
1337                         continue;
1338                 }
1339
1340                 /* Retrieve source file list. */
1341                 ret = dwarf_srcfiles(die, &src_files, &filecount, &de);
1342                 if (ret == DW_DLV_ERROR)
1343                         warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1344                 if (ret != DW_DLV_OK)
1345                         continue;
1346
1347                 /*
1348                  * Retrieve line number information from .debug_line section.
1349                  */
1350
1351                 ret = dwarf_srclines(die, &lbuf, &lcount, &de);
1352                 if (ret == DW_DLV_ERROR)
1353                         warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1354                 if (ret != DW_DLV_OK)
1355                         goto line_attr;
1356                 for (i = 0; (Dwarf_Signed) i < lcount; i++) {
1357                         if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
1358                                 warnx("dwarf_lineaddr: %s", dwarf_errmsg(de));
1359                                 continue;
1360                         }
1361                         if (dwarf_lineno(lbuf[i], &lineno, &de)) {
1362                                 warnx("dwarf_lineno: %s", dwarf_errmsg(de));
1363                                 continue;
1364                         }
1365                         if (dwarf_linesrc(lbuf[i], &sfile, &de)) {
1366                                 warnx("dwarf_linesrc: %s", dwarf_errmsg(de));
1367                                 continue;
1368                         }
1369                         if ((lie = malloc(sizeof(*lie))) == NULL) {
1370                                 warn("malloc");
1371                                 continue;
1372                         }
1373                         lie->addr = lineaddr;
1374                         lie->line = lineno;
1375                         lie->file = strdup(sfile);
1376                         if (lie->file == NULL) {
1377                                 warn("strdup");
1378                                 free(lie);
1379                                 continue;
1380                         }
1381                         SLIST_INSERT_HEAD(line_info, lie, entries);
1382                 }
1383
1384         line_attr:
1385                 /* Retrieve line number information from DIEs. */
1386                 search_line_attr(dbg, func_info, var_info, die, src_files, filecount);
1387         }
1388
1389         (void) dwarf_finish(dbg, &de);
1390
1391 process_sym:
1392
1393         p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx,
1394             type_table, (void *) sec_table, shnum);
1395
1396         if (p_data.list_num == 0)
1397                 goto next_cmd;
1398
1399         p_data.headp = &list_head;
1400         p_data.sh_num = shnum;
1401         p_data.t_table = type_table;
1402         p_data.s_table = (void *) sec_table;
1403         p_data.filename = filename;
1404         p_data.objname = objname;
1405
1406         sym_list_print(&p_data, func_info, var_info, line_info);
1407
1408 next_cmd:
1409         if (nm_opts.debug_line) {
1410                 if (func_info != NULL) {
1411                         while (!SLIST_EMPTY(func_info)) {
1412                                 func = SLIST_FIRST(func_info);
1413                                 SLIST_REMOVE_HEAD(func_info, entries);
1414                                 free(func->file);
1415                                 free(func->name);
1416                                 free(func);
1417                         }
1418                         free(func_info);
1419                         func_info = NULL;
1420                 }
1421                 if (var_info != NULL) {
1422                         while (!SLIST_EMPTY(var_info)) {
1423                                 var = SLIST_FIRST(var_info);
1424                                 SLIST_REMOVE_HEAD(var_info, entries);
1425                                 free(var->file);
1426                                 free(var->name);
1427                                 free(var);
1428                         }
1429                         free(var_info);
1430                         var_info = NULL;
1431                 }
1432                 if (line_info != NULL) {
1433                         while (!SLIST_EMPTY(line_info)) {
1434                                 lie = SLIST_FIRST(line_info);
1435                                 SLIST_REMOVE_HEAD(line_info, entries);
1436                                 free(lie->file);
1437                                 free(lie);
1438                         }
1439                         free(line_info);
1440                         line_info = NULL;
1441                 }
1442         }
1443
1444         if (sec_table != NULL)
1445                 for (i = 0; i < shnum; ++i)
1446                         free(sec_table[i]);
1447         free(sec_table);
1448         free(type_table);
1449
1450         sym_list_dest(&list_head);
1451
1452         return (rtn);
1453
1454 #undef  OBJNAME
1455 }
1456
1457 static int
1458 read_object(const char *filename)
1459 {
1460         Elf *elf, *arf;
1461         Elf_Cmd elf_cmd;
1462         Elf_Kind kind;
1463         int fd, rtn, e_err;
1464
1465         assert(filename != NULL && "filename is null");
1466
1467         if ((fd = open(filename, O_RDONLY)) == -1) {
1468                 warn("'%s'", filename);
1469                 return (1);
1470         }
1471
1472         elf_cmd = ELF_C_READ;
1473         if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) {
1474                 if ((e_err = elf_errno()) != 0)
1475                         warnx("elf_begin error: %s", elf_errmsg(e_err));
1476                 else
1477                         warnx("elf_begin error");
1478                 close(fd);
1479                 return (1);
1480         }
1481
1482         assert(arf != NULL && "arf is null.");
1483
1484         rtn = 0;
1485         if ((kind = elf_kind(arf)) == ELF_K_NONE) {
1486                 warnx("%s: File format not recognized", filename);
1487                 elf_end(arf);
1488                 close(fd);
1489                 return (1);
1490         }
1491         if (kind == ELF_K_AR) {
1492                 if (nm_opts.print_name == PRINT_NAME_MULTI &&
1493                     nm_opts.elem_print_fn == sym_elem_print_all)
1494                         printf("\n%s:\n", filename);
1495                 if (nm_opts.print_armap == true)
1496                         print_ar_index(fd, arf);
1497         }
1498
1499         while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) {
1500                 rtn |= read_elf(elf, filename, kind);
1501
1502                 /*
1503                  * If file is not archive, elf_next return ELF_C_NULL and
1504                  * stop the loop.
1505                  */
1506                 elf_cmd = elf_next(elf);
1507                 elf_end(elf);
1508         }
1509
1510         elf_end(arf);
1511         close(fd);
1512
1513         return (rtn);
1514 }
1515
1516 static int
1517 read_files(int argc, char **argv)
1518 {
1519         int rtn = 0;
1520
1521         if (argc < 0 || argv == NULL)
1522                 return (1);
1523
1524         if (argc == 0)
1525                 rtn |= read_object(nm_info.def_filename);
1526         else {
1527                 if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1)
1528                         nm_opts.print_name = PRINT_NAME_MULTI;
1529                 while (argc > 0) {
1530                         rtn |= read_object(*argv);
1531                         --argc;
1532                         ++argv;
1533                 }
1534         }
1535
1536         return (rtn);
1537 }
1538
1539 static void
1540 print_lineno(struct sym_entry *ep, struct func_info_head *func_info,
1541     struct var_info_head *var_info, struct line_info_head *line_info)
1542 {
1543         struct func_info_entry *func;
1544         struct var_info_entry *var;
1545         struct line_info_entry *lie;
1546
1547         /* For function symbol, search the function line information list.  */
1548         if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) {
1549                 SLIST_FOREACH(func, func_info, entries) {
1550                         if (func->name != NULL &&
1551                             !strcmp(ep->name, func->name) &&
1552                             ep->sym->st_value >= func->lowpc &&
1553                             ep->sym->st_value < func->highpc) {
1554                                 printf("\t%s:%" PRIu64, func->file, func->line);
1555                                 return;
1556                         }
1557                 }
1558         }
1559
1560         /* For variable symbol, search the variable line information list.  */
1561         if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) {
1562                 SLIST_FOREACH(var, var_info, entries) {
1563                         if (!strcmp(ep->name, var->name) &&
1564                             ep->sym->st_value == var->addr) {
1565                                 printf("\t%s:%" PRIu64, var->file, var->line);
1566                                 return;
1567                         }
1568                 }
1569         }
1570
1571         /* Otherwise search line number information the .debug_line section. */
1572         if (line_info != NULL) {
1573                 SLIST_FOREACH(lie, line_info, entries) {
1574                         if (ep->sym->st_value == lie->addr) {
1575                                 printf("\t%s:%" PRIu64, lie->file, lie->line);
1576                                 return;
1577                         }
1578                 }
1579         }
1580 }
1581
1582 static void
1583 set_opt_value_print_fn(enum radix t)
1584 {
1585
1586         switch (t) {
1587         case RADIX_OCT:
1588                 nm_opts.value_print_fn = &sym_value_oct_print;
1589                 nm_opts.size_print_fn = &sym_size_oct_print;
1590
1591                 break;
1592         case RADIX_DEC:
1593                 nm_opts.value_print_fn = &sym_value_dec_print;
1594                 nm_opts.size_print_fn = &sym_size_dec_print;
1595
1596                 break;
1597         case RADIX_HEX:
1598         default :
1599                 nm_opts.value_print_fn = &sym_value_hex_print;
1600                 nm_opts.size_print_fn  = &sym_size_hex_print;
1601         }
1602
1603         assert(nm_opts.value_print_fn != NULL &&
1604             "nm_opts.value_print_fn is null");
1605 }
1606
1607 static void
1608 sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym,
1609     const char *name)
1610 {
1611
1612         if (sec == NULL || sym == NULL || name == NULL ||
1613             nm_opts.value_print_fn == NULL)
1614                 return;
1615
1616         if (IS_UNDEF_SYM_TYPE(type)) {
1617                 if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32)
1618                         printf("%-8s", "");
1619                 else
1620                         printf("%-16s", "");
1621         } else {
1622                 switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) +
1623                     nm_opts.print_size) {
1624                 case 3:
1625                         if (sym->st_size != 0) {
1626                                 nm_opts.value_print_fn(sym);
1627                                 printf(" ");
1628                                 nm_opts.size_print_fn(sym);
1629                         }
1630                         break;
1631
1632                 case 2:
1633                         if (sym->st_size != 0)
1634                                 nm_opts.size_print_fn(sym);
1635                         break;
1636
1637                 case 1:
1638                         nm_opts.value_print_fn(sym);
1639                         if (sym->st_size != 0) {
1640                                 printf(" ");
1641                                 nm_opts.size_print_fn(sym);
1642                         }
1643                         break;
1644
1645                 case 0:
1646                 default:
1647                         nm_opts.value_print_fn(sym);
1648                 }
1649         }
1650
1651         printf(" %c ", type);
1652         PRINT_DEMANGLED_NAME("%s", name);
1653 }
1654
1655 static void
1656 sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym,
1657     const char *name)
1658 {
1659
1660         if (sec == NULL || sym == NULL || name == NULL ||
1661             nm_opts.value_print_fn == NULL)
1662                 return;
1663
1664         PRINT_DEMANGLED_NAME("%s", name);
1665         printf(" %c ", type);
1666         if (!IS_UNDEF_SYM_TYPE(type)) {
1667                 nm_opts.value_print_fn(sym);
1668                 printf(" ");
1669                 if (sym->st_size != 0)
1670                         nm_opts.size_print_fn(sym);
1671         } else
1672                 printf("        ");
1673 }
1674
1675 static void
1676 sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym,
1677     const char *name)
1678 {
1679
1680         if (sec == NULL || sym == NULL || name == NULL ||
1681             nm_opts.value_print_fn == NULL)
1682                 return;
1683
1684         PRINT_DEMANGLED_NAME("%-20s|", name);
1685         if (IS_UNDEF_SYM_TYPE(type))
1686                 printf("                ");
1687         else
1688                 nm_opts.value_print_fn(sym);
1689
1690         printf("|   %c  |", type);
1691
1692         switch (sym->st_info & 0xf) {
1693         case STT_OBJECT:
1694                 printf("%18s|", "OBJECT");
1695                 break;
1696
1697         case STT_FUNC:
1698                 printf("%18s|", "FUNC");
1699                 break;
1700
1701         case STT_SECTION:
1702                 printf("%18s|", "SECTION");
1703                 break;
1704
1705         case STT_FILE:
1706                 printf("%18s|", "FILE");
1707                 break;
1708
1709         case STT_LOPROC:
1710                 printf("%18s|", "LOPROC");
1711                 break;
1712
1713         case STT_HIPROC:
1714                 printf("%18s|", "HIPROC");
1715                 break;
1716
1717         case STT_NOTYPE:
1718         default:
1719                 printf("%18s|", "NOTYPE");
1720         }
1721
1722         if (sym->st_size != 0)
1723                 nm_opts.size_print_fn(sym);
1724         else
1725                 printf("                ");
1726
1727         printf("|     |%s", sec);
1728 }
1729
1730 static int
1731 sym_elem_def(char type, const GElf_Sym *sym, const char *name)
1732 {
1733
1734         assert(IS_SYM_TYPE((unsigned char) type));
1735
1736         UNUSED(sym);
1737         UNUSED(name);
1738
1739         return (!IS_UNDEF_SYM_TYPE((unsigned char) type));
1740 }
1741
1742 static int
1743 sym_elem_global(char type, const GElf_Sym *sym, const char *name)
1744 {
1745
1746         assert(IS_SYM_TYPE((unsigned char) type));
1747
1748         UNUSED(sym);
1749         UNUSED(name);
1750
1751         /* weak symbols resemble global. */
1752         return (isupper((unsigned char) type) || type == 'w');
1753 }
1754
1755 static int
1756 sym_elem_global_static(char type, const GElf_Sym *sym, const char *name)
1757 {
1758         unsigned char info;
1759
1760         assert(sym != NULL);
1761
1762         UNUSED(type);
1763         UNUSED(name);
1764
1765         info = sym->st_info >> 4;
1766
1767         return (info == STB_LOCAL ||
1768             info == STB_GLOBAL ||
1769             info == STB_WEAK);
1770 }
1771
1772 static int
1773 sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name)
1774 {
1775
1776         assert(sym != NULL);
1777
1778         UNUSED(type);
1779         UNUSED(name);
1780
1781         if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE)
1782                 return (0);
1783         if (sym->st_name == 0)
1784                 return (0);
1785
1786         return (1);
1787 }
1788
1789 static int
1790 sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name)
1791 {
1792
1793         assert(sym != NULL);
1794
1795         UNUSED(type);
1796         UNUSED(name);
1797
1798         return (sym->st_size > 0);
1799 }
1800
1801 static int
1802 sym_elem_undef(char type, const GElf_Sym *sym, const char *name)
1803 {
1804
1805         assert(IS_SYM_TYPE((unsigned char) type));
1806
1807         UNUSED(sym);
1808         UNUSED(name);
1809
1810         return (IS_UNDEF_SYM_TYPE((unsigned char) type));
1811 }
1812
1813 static void
1814 sym_list_dest(struct sym_head *headp)
1815 {
1816         struct sym_entry *ep, *ep_n;
1817
1818         if (headp == NULL)
1819                 return;
1820
1821         ep = STAILQ_FIRST(headp);
1822         while (ep != NULL) {
1823                 ep_n = STAILQ_NEXT(ep, sym_entries);
1824                 free(ep->sym);
1825                 free(ep->name);
1826                 free(ep);
1827                 ep = ep_n;
1828         }
1829 }
1830
1831 static int
1832 sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym)
1833 {
1834         struct sym_entry *e;
1835
1836         if (headp == NULL || name == NULL || sym == NULL)
1837                 return (0);
1838         if ((e = malloc(sizeof(struct sym_entry))) == NULL) {
1839                 warn("malloc");
1840                 return (0);
1841         }
1842         if ((e->name = strdup(name)) == NULL) {
1843                 warn("strdup");
1844                 free(e);
1845                 return (0);
1846         }
1847         if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) {
1848                 warn("malloc");
1849                 free(e->name);
1850                 free(e);
1851                 return (0);
1852         }
1853
1854         memcpy(e->sym, sym, sizeof(GElf_Sym));
1855
1856         /* Display size instead of value for common symbol. */
1857         if (sym->st_shndx == SHN_COMMON)
1858                 e->sym->st_value = sym->st_size;
1859
1860         STAILQ_INSERT_TAIL(headp, e, sym_entries);
1861
1862         return (1);
1863 }
1864
1865 /* If file has not .debug_info, line_info will be NULL */
1866 static void
1867 sym_list_print(struct sym_print_data *p, struct func_info_head *func_info,
1868     struct var_info_head *var_info, struct line_info_head *line_info)
1869 {
1870         struct sym_entry *e_v;
1871         size_t si;
1872         int i;
1873
1874         if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1875                 return;
1876         if ((e_v = sym_list_sort(p)) == NULL)
1877                 return;
1878         if (nm_opts.sort_reverse == false)
1879                 for (si = 0; si != p->list_num; ++si)
1880                         sym_list_print_each(&e_v[si], p, func_info, var_info,
1881                             line_info);
1882         else
1883                 for (i = p->list_num - 1; i != -1; --i)
1884                         sym_list_print_each(&e_v[i], p, func_info, var_info,
1885                             line_info);
1886
1887         free(e_v);
1888 }
1889
1890 /* If file has not .debug_info, line_info will be NULL */
1891 static void
1892 sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p,
1893     struct func_info_head *func_info, struct var_info_head *var_info,
1894     struct line_info_head *line_info)
1895 {
1896         const char *sec;
1897         char type;
1898
1899         if (ep == NULL || CHECK_SYM_PRINT_DATA(p))
1900                 return;
1901
1902         assert(ep->name != NULL);
1903         assert(ep->sym != NULL);
1904
1905         type = get_sym_type(ep->sym, p->t_table);
1906
1907         if (nm_opts.print_name == PRINT_NAME_FULL) {
1908                 printf("%s", p->filename);
1909                 if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) {
1910                         if (p->objname != NULL)
1911                                 printf("[%s]", p->objname);
1912                         printf(": ");
1913                 } else {
1914                         if (p->objname != NULL)
1915                                 printf(":%s", p->objname);
1916                         printf(":");
1917                 }
1918         }
1919
1920         switch (ep->sym->st_shndx) {
1921         case SHN_LOPROC:
1922                 /* LOPROC or LORESERVE */
1923                 sec = "*LOPROC*";
1924                 break;
1925         case SHN_HIPROC:
1926                 sec = "*HIPROC*";
1927                 break;
1928         case SHN_LOOS:
1929                 sec = "*LOOS*";
1930                 break;
1931         case SHN_HIOS:
1932                 sec = "*HIOS*";
1933                 break;
1934         case SHN_ABS:
1935                 sec = "*ABS*";
1936                 break;
1937         case SHN_COMMON:
1938                 sec = "*COM*";
1939                 break;
1940         case SHN_HIRESERVE:
1941                 /* HIRESERVE or XINDEX */
1942                 sec = "*HIRESERVE*";
1943                 break;
1944         default:
1945                 if (ep->sym->st_shndx > p->sh_num)
1946                         return;
1947                 sec = p->s_table[ep->sym->st_shndx];
1948                 break;
1949         }
1950
1951         nm_opts.elem_print_fn(type, sec, ep->sym, ep->name);
1952
1953         if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type))
1954                 print_lineno(ep, func_info, var_info, line_info);
1955
1956         printf("\n");
1957 }
1958
1959 static struct sym_entry *
1960 sym_list_sort(struct sym_print_data *p)
1961 {
1962         struct sym_entry *ep, *e_v;
1963         int idx;
1964
1965         if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1966                 return (NULL);
1967
1968         if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) {
1969                 warn("malloc");
1970                 return (NULL);
1971         }
1972
1973         idx = 0;
1974         STAILQ_FOREACH(ep, p->headp, sym_entries) {
1975                 if (ep->name != NULL && ep->sym != NULL) {
1976                         e_v[idx].name = ep->name;
1977                         e_v[idx].sym = ep->sym;
1978                         ++idx;
1979                 }
1980         }
1981
1982         assert((size_t)idx == p->list_num);
1983
1984         if (nm_opts.sort_fn != &cmp_none) {
1985                 nm_print_data = p;
1986                 assert(nm_print_data != NULL);
1987                 qsort(e_v, p->list_num, sizeof(struct sym_entry),
1988                     nm_opts.sort_fn);
1989         }
1990
1991         return (e_v);
1992 }
1993
1994 static void
1995 sym_size_oct_print(const GElf_Sym *sym)
1996 {
1997
1998         assert(sym != NULL && "sym is null");
1999         printf("%016" PRIo64, sym->st_size);
2000 }
2001
2002 static void
2003 sym_size_hex_print(const GElf_Sym *sym)
2004 {
2005
2006         assert(sym != NULL && "sym is null");
2007         if (nm_elfclass == ELFCLASS32)
2008                 printf("%08" PRIx64, sym->st_size);
2009         else
2010                 printf("%016" PRIx64, sym->st_size);
2011 }
2012
2013 static void
2014 sym_size_dec_print(const GElf_Sym *sym)
2015 {
2016
2017         assert(sym != NULL && "sym is null");
2018         printf("%016" PRId64, sym->st_size);
2019 }
2020
2021 static void
2022 sym_value_oct_print(const GElf_Sym *sym)
2023 {
2024
2025         assert(sym != NULL && "sym is null");
2026         printf("%016" PRIo64, sym->st_value);
2027 }
2028
2029 static void
2030 sym_value_hex_print(const GElf_Sym *sym)
2031 {
2032
2033         assert(sym != NULL && "sym is null");
2034         if (nm_elfclass == ELFCLASS32)
2035                 printf("%08" PRIx64, sym->st_value);
2036         else
2037                 printf("%016" PRIx64, sym->st_value);
2038 }
2039
2040 static void
2041 sym_value_dec_print(const GElf_Sym *sym)
2042 {
2043
2044         assert(sym != NULL && "sym is null");
2045         printf("%016" PRId64, sym->st_value);
2046 }
2047
2048 static void
2049 usage(int exitcode)
2050 {
2051
2052         printf("Usage: %s [options] file ...\
2053 \n  Display symbolic information in file.\n\
2054 \n  Options: \
2055 \n  -A, --print-file-name     Write the full pathname or library name of an\
2056 \n                            object on each line.\
2057 \n  -a, --debug-syms          Display all symbols include debugger-only\
2058 \n                            symbols.", nm_info.name);
2059         printf("\
2060 \n  -B                        Equivalent to specifying \"--format=bsd\".\
2061 \n  -C, --demangle[=style]    Decode low-level symbol names.\
2062 \n      --no-demangle         Do not demangle low-level symbol names.\
2063 \n  -D, --dynamic             Display only dynamic symbols.\
2064 \n  -e                        Display only global and static symbols.");
2065         printf("\
2066 \n  -f                        Produce full output (default).\
2067 \n      --format=format       Display output in specific format.  Allowed\
2068 \n                            formats are: \"bsd\", \"posix\" and \"sysv\".\
2069 \n  -g, --extern-only         Display only global symbol information.\
2070 \n  -h, --help                Show this help message.\
2071 \n  -l, --line-numbers        Display filename and linenumber using\
2072 \n                            debugging information.\
2073 \n  -n, --numeric-sort        Sort symbols numerically by value.");
2074         printf("\
2075 \n  -o                        Write numeric values in octal. Equivalent to\
2076 \n                            specifying \"-t o\".\
2077 \n  -p, --no-sort             Do not sort symbols.\
2078 \n  -P                        Write information in a portable output format.\
2079 \n                            Equivalent to specifying \"--format=posix\".\
2080 \n  -r, --reverse-sort        Reverse the order of the sort.\
2081 \n  -S, --print-size          Print symbol sizes instead values.\
2082 \n  -s, --print-armap         Include an index of archive members.\
2083 \n      --size-sort           Sort symbols by size.");
2084         printf("\
2085 \n  -t, --radix=format        Write each numeric value in the specified\
2086 \n                            format:\
2087 \n                               d   In decimal,\
2088 \n                               o   In octal,\
2089 \n                               x   In hexadecimal.");
2090         printf("\
2091 \n  -u, --undefined-only      Display only undefined symbols.\
2092 \n      --defined-only        Display only defined symbols.\
2093 \n  -V, --version             Show the version identifier for %s.\
2094 \n  -v                        Sort output by value.\
2095 \n  -x                        Write numeric values in hexadecimal.\
2096 \n                            Equivalent to specifying \"-t x\".",
2097             nm_info.name);
2098         printf("\n\
2099 \n  The default options are: output in bsd format, use a hexadecimal radix,\
2100 \n  sort by symbol name, do not demangle names.\n");
2101
2102         exit(exitcode);
2103 }
2104
2105 /*
2106  * Display symbolic information in file.
2107  * Return 0 at success, >0 at failed.
2108  */
2109 int
2110 main(int argc, char **argv)
2111 {
2112         int rtn;
2113
2114         global_init();
2115         get_opt(argc, argv);
2116         rtn = read_files(argc - optind, argv + optind);
2117         global_dest();
2118
2119         exit(rtn);
2120 }