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