2 * Copyright (c) 2007 Hyogeol Lee <hyogeollee@gmail.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
27 #include <sys/queue.h>
28 #include <sys/types.h>
51 ELFTC_VCSID("$Id: nm.c 2484 2012-04-07 15:52:05Z kaiwang27 $");
53 /* symbol information list */
54 STAILQ_HEAD(sym_head, sym_entry);
59 STAILQ_ENTRY(sym_entry) sym_entries;
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 *);
67 /* output filter list */
68 static SLIST_HEAD(filter_head, filter_entry) nm_out_filter =
69 SLIST_HEAD_INITIALIZER(nm_out_filter);
73 SLIST_ENTRY(filter_entry) filter_entries;
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;
84 const char *def_filename;
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;
94 SLIST_HEAD(line_info_head, line_info_entry);
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;
105 SLIST_HEAD(func_info_head, func_info_entry);
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;
115 SLIST_HEAD(var_info_head, var_info_entry);
117 /* output numric type */
124 /* output symbol type, PRINT_SYM_DYN for dynamic symbol only */
130 /* output name type */
137 struct nm_prog_options {
138 enum print_symbol print_symbol;
139 enum print_name print_name;
153 * function pointer to sort symbol list.
154 * possible function - cmp_name, cmp_none, cmp_size, cmp_value
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
164 fn_elem_print elem_print_fn;
166 fn_sym_print value_print_fn;
167 fn_sym_print size_print_fn;
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)
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,
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 *,
206 static int sym_elem_nondebug(char, const GElf_Sym *, const char *);
207 static int sym_elem_nonzero_size(char, const GElf_Sym *,
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 *,
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);
234 static struct nm_prog_info nm_info;
235 static struct nm_prog_options nm_opts;
236 static int nm_elfclass;
239 * Point to current sym_print_data to use portable qsort function.
240 * (e.g. There is no qsort_r function in NetBSD.)
242 * Using in sym_list_sort.
244 static struct sym_print_data *nm_print_data;
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 { "format", required_argument, NULL, 'F' },
252 { "help", no_argument, NULL, 'h' },
253 { "line-numbers", no_argument, NULL, 'l' },
254 { "no-demangle", no_argument, &nm_opts.no_demangle,
256 { "no-sort", no_argument, NULL, 'p' },
257 { "numeric-sort", no_argument, NULL, 'v' },
258 { "print-armap", no_argument, NULL, 's' },
259 { "print-file-name", no_argument, NULL, 'A' },
260 { "print-size", no_argument, NULL, 'S' },
261 { "radix", required_argument, NULL, 't' },
262 { "reverse-sort", no_argument, NULL, 'r' },
263 { "size-sort", no_argument, &nm_opts.sort_size, 1},
264 { "undefined-only", no_argument, NULL, 'u' },
265 { "version", no_argument, NULL, 'V' },
269 #if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS)
270 static __inline uint32_t
271 be32dec(const void *pp)
273 unsigned char const *p = (unsigned char const *)pp;
275 return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
278 static __inline uint32_t
279 le32dec(const void *pp)
281 unsigned char const *p = (unsigned char const *)pp;
283 return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
286 static __inline uint64_t
287 be64dec(const void *pp)
289 unsigned char const *p = (unsigned char const *)pp;
291 return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
294 static __inline uint64_t
295 le64dec(const void *pp)
297 unsigned char const *p = (unsigned char const *)pp;
299 return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
304 cmp_name(const void *l, const void *r)
309 assert(((const struct sym_entry *)l)->name != NULL);
310 assert(((const struct sym_entry *)r)->name != NULL);
312 return (strcmp(((const struct sym_entry *)l)->name,
313 ((const struct sym_entry *)r)->name));
317 cmp_none(const void *l, const void *r)
326 /* Size comparison. If l and r have same size, compare their name. */
328 cmp_size(const void *lp, const void *rp)
330 const struct sym_entry *l, *r;
336 assert(l->name != NULL);
337 assert(l->sym != NULL);
339 assert(r->name != NULL);
340 assert(r->sym != NULL);
342 if (l->sym->st_size == r->sym->st_size)
343 return (strcmp(l->name, r->name));
345 return (l->sym->st_size - r->sym->st_size);
348 /* Value comparison. Undefined symbols come first. */
350 cmp_value(const void *lp, const void *rp)
352 const struct sym_entry *l, *r;
354 int l_is_undef, r_is_undef;
359 assert(nm_print_data != NULL);
360 ttable = nm_print_data->t_table;
363 assert(l->name != NULL);
364 assert(l->sym != NULL);
366 assert(r->name != NULL);
367 assert(r->sym != NULL);
368 assert(ttable != NULL);
370 l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0;
371 r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0;
373 assert(l_is_undef + r_is_undef >= 0);
374 assert(l_is_undef + r_is_undef <= 2);
376 switch (l_is_undef + r_is_undef) {
379 if (l->sym->st_value == r->sym->st_value)
380 return (strcmp(l->name, r->name));
381 return (l->sym->st_value - r->sym->st_value);
384 return (l_is_undef == 0 ? 1 : -1);
387 return (strcmp(l->name, r->name));
391 return (l->sym->st_value - r->sym->st_value);
397 struct filter_entry *e;
399 while (!SLIST_EMPTY(&nm_out_filter)) {
400 e = SLIST_FIRST(&nm_out_filter);
401 SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries);
407 filter_insert(fn_filter filter_fn)
409 struct filter_entry *e;
411 assert(filter_fn != NULL);
413 if ((e = malloc(sizeof(struct filter_entry))) == NULL) {
418 SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries);
424 parse_demangle_option(const char *opt)
428 return (ELFTC_DEM_UNKNOWN);
429 else if (!strncasecmp(opt, "gnu-v2", 6))
430 return (ELFTC_DEM_GNU2);
431 else if (!strncasecmp(opt, "gnu-v3", 6))
432 return (ELFTC_DEM_GNU3);
433 else if (!strncasecmp(opt, "arm", 3))
434 return (ELFTC_DEM_ARM);
436 errx(EXIT_FAILURE, "unknown demangling style '%s'", opt);
443 get_opt(int argc, char **argv)
446 bool is_posix, oflag;
448 if (argc <= 0 || argv == NULL)
451 oflag = is_posix = false;
452 nm_opts.t = RADIX_HEX;
453 while ((ch = getopt_long(argc, argv, "ABCDF:PSVaefghlnoprst:uvx",
454 nm_longopts, NULL)) != -1) {
457 nm_opts.print_name = PRINT_NAME_FULL;
460 nm_opts.elem_print_fn = &sym_elem_print_all;
463 nm_opts.demangle_type = parse_demangle_option(optarg);
466 nm_opts.print_symbol = PRINT_SYM_DYN;
469 /* sysv, bsd, posix */
473 nm_opts.elem_print_fn = &sym_elem_print_all;
478 nm_opts.elem_print_fn =
479 &sym_elem_print_all_portable;
483 nm_opts.elem_print_fn =
484 &sym_elem_print_all_sysv;
487 warnx("%s: Invalid format", optarg);
494 nm_opts.elem_print_fn = &sym_elem_print_all_portable;
497 nm_opts.print_size = 1;
503 nm_opts.print_debug = true;
506 filter_insert(sym_elem_global_static);
511 filter_insert(sym_elem_global);
517 nm_opts.debug_line = true;
521 nm_opts.sort_fn = &cmp_value;
527 nm_opts.sort_fn = &cmp_none;
530 nm_opts.sort_reverse = true;
533 nm_opts.print_armap = true;
536 /* t require always argument to getopt_long */
539 nm_opts.t = RADIX_DEC;
542 nm_opts.t = RADIX_OCT;
545 nm_opts.t = RADIX_HEX;
548 warnx("%s: Invalid radix", optarg);
553 filter_insert(sym_elem_undef);
554 nm_opts.undef_only = true;
556 /* case 'v': see case 'n' above. */
558 nm_opts.t = RADIX_HEX;
561 if (nm_opts.sort_size != 0) {
562 nm_opts.sort_fn = &cmp_size;
563 filter_insert(sym_elem_def);
564 filter_insert(sym_elem_nonzero_size);
566 if (nm_opts.def_only != 0)
567 filter_insert(sym_elem_def);
568 if (nm_opts.no_demangle != 0)
569 nm_opts.demangle_type = -1;
577 * In POSIX mode, the '-o' option controls the output radix.
578 * In non-POSIX mode, the option is a synonym for the '-A' and
579 * '--print-file-name' options.
583 nm_opts.t = RADIX_OCT;
585 nm_opts.print_name = PRINT_NAME_FULL;
588 assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null");
589 assert(nm_opts.elem_print_fn != NULL &&
590 "nm_opts.elem_print_fn is null");
591 assert(nm_opts.value_print_fn != NULL &&
592 "nm_opts.value_print_fn is null");
594 set_opt_value_print_fn(nm_opts.t);
596 if (nm_opts.undef_only == true) {
597 if (nm_opts.sort_fn == &cmp_size)
599 "--size-sort with -u is meaningless");
600 if (nm_opts.def_only != 0)
602 "-u with --defined-only is meaningless");
604 if (nm_opts.print_debug == false)
605 filter_insert(sym_elem_nondebug);
606 if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none)
607 nm_opts.sort_reverse = false;
611 * Get symbol information from elf.
614 get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx,
615 size_t strndx, const char *type_table, const char **sec_table,
622 struct filter_entry *fep;
625 const char *sym_name;
631 assert(headp != NULL);
634 for (i = 1; i < shnum; i++) {
635 if ((scn = elf_getscn(elf, i)) == NULL) {
636 warnx("elf_getscn failed: %s", elf_errmsg(-1));
639 if (gelf_getshdr(scn, &shdr) != &shdr) {
640 warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
643 if (shdr.sh_type == SHT_SYMTAB) {
644 if (nm_opts.print_symbol != PRINT_SYM_SYM)
646 } else if (shdr.sh_type == SHT_DYNSYM) {
647 if (nm_opts.print_symbol != PRINT_SYM_DYN)
652 ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx;
655 while ((data = elf_getdata(scn, data)) != NULL) {
657 while (gelf_getsym(data, j++, &sym) != NULL) {
658 sym_name = get_sym_name(elf, &sym, ndx,
659 sec_table, sec_table_size);
661 type = get_sym_type(&sym, type_table);
662 SLIST_FOREACH(fep, &nm_out_filter,
664 if (!fep->fn(type, &sym, sym_name)) {
669 if (filter == false) {
670 if (sym_list_insert(headp, sym_name,
683 get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table,
686 const char *sym_name;
690 /* Show section name as symbol name for STT_SECTION symbols. */
691 if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) {
692 if (sec_table != NULL && sym->st_shndx < sec_table_size)
693 sym_name = sec_table[sym->st_shndx];
695 sym_name = elf_strptr(elf, ndx, sym->st_name);
697 if (sym_name == NULL)
704 get_sym_type(const GElf_Sym *sym, const char *type_table)
708 if (sym == NULL || type_table == NULL)
711 is_local = sym->st_info >> 4 == STB_LOCAL;
713 if (sym->st_shndx == SHN_ABS) /* absolute */
714 return (is_local ? 'a' : 'A');
716 if (sym->st_shndx == SHN_COMMON) /* common */
719 if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */
720 if ((sym->st_info & 0xf) == STT_OBJECT)
721 return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V');
723 return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W');
726 if (sym->st_shndx == SHN_UNDEF) /* undefined */
729 return (is_local == true && type_table[sym->st_shndx] != 'N' ?
730 tolower((unsigned char) type_table[sym->st_shndx]) :
731 type_table[sym->st_shndx]);
745 if (elf_version(EV_CURRENT) == EV_NONE)
746 errx(EXIT_FAILURE, "elf_version error");
748 nm_info.name = ELFTC_GETPROGNAME();
749 nm_info.def_filename = "a.out";
750 nm_opts.print_symbol = PRINT_SYM_SYM;
751 nm_opts.print_name = PRINT_NAME_NONE;
752 nm_opts.demangle_type = -1;
753 nm_opts.print_debug = false;
754 nm_opts.print_armap = false;
755 nm_opts.print_size = 0;
756 nm_opts.debug_line = false;
757 nm_opts.def_only = 0;
758 nm_opts.undef_only = false;
759 nm_opts.sort_size = 0;
760 nm_opts.sort_reverse = false;
761 nm_opts.no_demangle = 0;
762 nm_opts.sort_fn = &cmp_name;
763 nm_opts.elem_print_fn = &sym_elem_print_all;
764 nm_opts.value_print_fn = &sym_value_dec_print;
765 nm_opts.size_print_fn = &sym_size_dec_print;
766 SLIST_INIT(&nm_out_filter);
770 is_sec_data(GElf_Shdr *s)
773 assert(s != NULL && "shdr is NULL");
775 return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS);
779 is_sec_debug(const char *shname)
781 const char *dbg_sec[] = {
792 assert(shname != NULL && "shname is NULL");
794 for (p = dbg_sec; *p; p++) {
795 if (!strncmp(shname, *p, strlen(*p)))
803 is_sec_nobits(GElf_Shdr *s)
806 assert(s != NULL && "shdr is NULL");
808 return (s->sh_type == SHT_NOBITS);
812 is_sec_readonly(GElf_Shdr *s)
815 assert(s != NULL && "shdr is NULL");
817 return ((s->sh_flags & SHF_WRITE) == 0);
821 is_sec_text(GElf_Shdr *s)
824 assert(s != NULL && "shdr is NULL");
826 return ((s->sh_flags & SHF_EXECINSTR) != 0);
830 print_ar_index(int fd, Elf *arf)
842 if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL)
845 printf("\nArchive index:\n");
847 start = arsym->as_off;
849 while (arsym_size > 1) {
850 if (elf_rand(arf, arsym->as_off) == arsym->as_off &&
851 (elf = elf_begin(fd, cmd, arf)) != NULL) {
852 if ((arhdr = elf_getarhdr(elf)) != NULL)
853 printf("%s in %s\n", arsym->as_name,
854 arhdr->ar_name != NULL ?
855 arhdr->ar_name : arhdr->ar_rawname);
862 elf_rand(arf, start);
865 #define DEMANGLED_BUFFER_SIZE (8 * 1024)
866 #define PRINT_DEMANGLED_NAME(FORMAT, NAME) do { \
867 char _demangled[DEMANGLED_BUFFER_SIZE]; \
868 if (nm_opts.demangle_type < 0 || \
869 elftc_demangle((NAME), _demangled, sizeof(_demangled), \
870 nm_opts.demangle_type) < 0) \
871 printf((FORMAT), (NAME)); \
873 printf((FORMAT), _demangled); \
877 print_header(const char *file, const char *obj)
883 if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) {
884 printf("\n\n%s from %s",
885 nm_opts.undef_only == false ? "Symbols" :
886 "Undefined symbols", file);
892 Name Value Class Type Size Line Section\n\n");
894 /* archive file without -A option and POSIX */
895 if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) {
896 if (nm_opts.elem_print_fn ==
897 sym_elem_print_all_portable)
898 printf("%s[%s]:\n", file, obj);
899 else if (nm_opts.elem_print_fn == sym_elem_print_all)
900 printf("\n%s:\n", obj);
901 /* multiple files(not archive) without -A option */
902 } else if (nm_opts.print_name == PRINT_NAME_MULTI) {
903 if (nm_opts.elem_print_fn == sym_elem_print_all)
905 printf("%s:\n", file);
914 (void) printf("%s (%s)\n", nm_info.name, elftc_version());
919 get_block_value(Dwarf_Debug dbg, Dwarf_Block *block)
925 if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) {
926 warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de));
930 if (gelf_getehdr(elf, &eh) != &eh) {
931 warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
935 if (block->bl_len == 5) {
936 if (eh.e_ident[EI_DATA] == ELFDATA2LSB)
937 return (le32dec((uint8_t *) block->bl_data + 1));
939 return (be32dec((uint8_t *) block->bl_data + 1));
940 } else if (block->bl_len == 9) {
941 if (eh.e_ident[EI_DATA] == ELFDATA2LSB)
942 return (le64dec((uint8_t *) block->bl_data + 1));
944 return (be64dec((uint8_t *) block->bl_data + 1));
951 search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info,
952 struct var_info_head *var_info, Dwarf_Die die, char **src_files,
953 Dwarf_Signed filecount)
956 Dwarf_Unsigned udata;
962 struct func_info_entry *func;
963 struct var_info_entry *var;
967 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
968 warnx("dwarf_tag failed: %s", dwarf_errmsg(de));
972 /* We're interested in DIEs which define functions or variables. */
973 if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point &&
974 tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable)
977 if (tag == DW_TAG_variable) {
979 /* Ignore "artificial" variable. */
980 if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) ==
984 /* Ignore pure declaration. */
985 if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) ==
989 /* Ignore stack varaibles. */
990 if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) !=
994 if ((var = calloc(1, sizeof(*var))) == NULL) {
995 warn("calloc failed");
999 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata,
1000 &de) == DW_DLV_OK && udata > 0 &&
1001 (Dwarf_Signed) (udata - 1) < filecount) {
1002 var->file = strdup(src_files[udata - 1]);
1003 if (var->file == NULL) {
1010 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) ==
1014 if (dwarf_attrval_string(die, DW_AT_name, &str, &de) ==
1016 var->name = strdup(str);
1017 if (var->name == NULL) {
1026 if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK &&
1027 dwarf_formblock(at, &block, &de) == DW_DLV_OK) {
1029 * Since we ignored stack variables, the rest are the
1030 * external varaibles which should always use DW_OP_addr
1031 * operator for DW_AT_location value.
1033 if (*((uint8_t *)block->bl_data) == DW_OP_addr)
1034 var->addr = get_block_value(dbg, block);
1037 SLIST_INSERT_HEAD(var_info, var, entries);
1041 if ((func = calloc(1, sizeof(*func))) == NULL) {
1042 warn("calloc failed");
1047 * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin
1048 * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line
1049 * attributes for inlined functions as well.
1051 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata,
1052 &de) == DW_DLV_OK && udata > 0 &&
1053 (Dwarf_Signed) (udata - 1) < filecount) {
1054 func->file = strdup(src_files[udata - 1]);
1055 if (func->file == NULL) {
1062 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) ==
1066 if (dwarf_attrval_string(die, DW_AT_name, &str, &de) ==
1068 func->name = strdup(str);
1069 if (func->name == NULL) {
1078 if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) ==
1080 func->lowpc = udata;
1081 if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) ==
1083 func->highpc = udata;
1085 SLIST_INSERT_HEAD(func_info, func, entries);
1090 /* Search children. */
1091 ret = dwarf_child(die, &ret_die, &de);
1092 if (ret == DW_DLV_ERROR)
1093 warnx("dwarf_child: %s", dwarf_errmsg(de));
1094 else if (ret == DW_DLV_OK)
1095 search_line_attr(dbg, func_info, var_info, ret_die, src_files,
1098 /* Search sibling. */
1099 ret = dwarf_siblingof(dbg, die, &ret_die, &de);
1100 if (ret == DW_DLV_ERROR)
1101 warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
1102 else if (ret == DW_DLV_OK)
1103 search_line_attr(dbg, func_info, var_info, ret_die, src_files,
1106 dwarf_dealloc(dbg, die, DW_DLA_DIE);
1110 * Read elf file and collect symbol information, sort them, print.
1111 * Return 1 at failed, 0 at success.
1114 read_elf(Elf *elf, const char *filename, Elf_Kind kind)
1125 Dwarf_Unsigned lineno;
1126 Dwarf_Signed lcount, filecount;
1127 Dwarf_Addr lineaddr;
1128 struct sym_print_data p_data;
1129 struct sym_head list_head;
1130 struct line_info_head *line_info;
1131 struct func_info_head *func_info;
1132 struct var_info_head *var_info;
1133 struct line_info_entry *lie;
1134 struct func_info_entry *func;
1135 struct var_info_entry *var;
1136 const char *shname, *objname;
1137 char *type_table, **sec_table, *sfile, **src_files;
1138 size_t shstrndx, shnum, dynndx, strndx;
1139 int ret, rtn, e_err;
1141 #define OBJNAME (objname == NULL ? filename : objname)
1143 assert(filename != NULL && "filename is null");
1145 STAILQ_INIT(&list_head);
1156 nm_elfclass = gelf_getclass(elf);
1158 if (kind == ELF_K_AR) {
1159 if ((arhdr = elf_getarhdr(elf)) == NULL)
1161 objname = arhdr->ar_name != NULL ? arhdr->ar_name :
1164 if (!elf_getshnum(elf, &shnum)) {
1165 if ((e_err = elf_errno()) != 0)
1166 warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1168 warnx("%s: cannot get section number", OBJNAME);
1173 warnx("%s: has no section", OBJNAME);
1177 if (!elf_getshstrndx(elf, &shstrndx)) {
1178 warnx("%s: cannot get str index", OBJNAME);
1182 /* type_table for type determine */
1183 if ((type_table = malloc(sizeof(char) * shnum)) == NULL) {
1184 warn("%s: malloc", OBJNAME);
1188 /* sec_table for section name to display in sysv format */
1189 if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) {
1190 warn("%s: calloc", OBJNAME);
1195 type_table[0] = 'U';
1196 if ((sec_table[0] = strdup("*UND*")) == NULL) {
1201 for (i = 1; i < shnum; ++i) {
1202 type_table[i] = 'U';
1203 if ((scn = elf_getscn(elf, i)) == NULL) {
1204 if ((e_err = elf_errno()) != 0)
1205 warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1207 warnx("%s: cannot get section", OBJNAME);
1211 if (gelf_getshdr(scn, &shdr) == NULL)
1215 * Cannot test by type and attribute for dynstr, strtab
1217 shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name);
1218 if (shname != NULL) {
1219 if ((sec_table[i] = strdup(shname)) == NULL) {
1223 if (!strncmp(shname, ".dynstr", 7)) {
1224 dynndx = elf_ndxscn(scn);
1225 if (dynndx == SHN_UNDEF) {
1226 warnx("%s: elf_ndxscn failed: %s",
1227 OBJNAME, elf_errmsg(-1));
1231 if (!strncmp(shname, ".strtab", 7)) {
1232 strndx = elf_ndxscn(scn);
1233 if (strndx == SHN_UNDEF) {
1234 warnx("%s: elf_ndxscn failed: %s",
1235 OBJNAME, elf_errmsg(-1));
1240 sec_table[i] = strdup("*UND*");
1241 if (sec_table[i] == NULL) {
1248 if (is_sec_text(&shdr))
1249 type_table[i] = 'T';
1250 else if (is_sec_data(&shdr)) {
1251 if (is_sec_readonly(&shdr))
1252 type_table[i] = 'R';
1254 type_table[i] = 'D';
1255 } else if (is_sec_nobits(&shdr))
1256 type_table[i] = 'B';
1257 else if (is_sec_debug(shname))
1258 type_table[i] = 'N';
1259 else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr))
1260 type_table[i] = 'n';
1263 print_header(filename, objname);
1265 if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) ||
1266 (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) {
1267 warnx("%s: no symbols", OBJNAME);
1268 /* This is not an error case */
1272 STAILQ_INIT(&list_head);
1274 if (!nm_opts.debug_line)
1278 * Collect dwarf line number information.
1281 if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) !=
1283 warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de));
1287 line_info = malloc(sizeof(struct line_info_head));
1288 func_info = malloc(sizeof(struct func_info_head));
1289 var_info = malloc(sizeof(struct var_info_head));
1290 if (line_info == NULL || func_info == NULL || var_info == NULL) {
1292 (void) dwarf_finish(dbg, &de);
1295 SLIST_INIT(line_info);
1296 SLIST_INIT(func_info);
1297 SLIST_INIT(var_info);
1299 while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
1300 &de)) == DW_DLV_OK) {
1302 while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
1303 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
1304 warnx("dwarf_tag failed: %s",
1308 /* XXX: What about DW_TAG_partial_unit? */
1309 if (tag == DW_TAG_compile_unit)
1313 warnx("could not find DW_TAG_compile_unit die");
1317 /* Retrieve source file list. */
1318 ret = dwarf_srcfiles(die, &src_files, &filecount, &de);
1319 if (ret == DW_DLV_ERROR)
1320 warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1321 if (ret != DW_DLV_OK)
1325 * Retrieve line number information from .debug_line section.
1328 ret = dwarf_srclines(die, &lbuf, &lcount, &de);
1329 if (ret == DW_DLV_ERROR)
1330 warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1331 if (ret != DW_DLV_OK)
1333 for (i = 0; (Dwarf_Signed) i < lcount; i++) {
1334 if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
1335 warnx("dwarf_lineaddr: %s", dwarf_errmsg(de));
1338 if (dwarf_lineno(lbuf[i], &lineno, &de)) {
1339 warnx("dwarf_lineno: %s", dwarf_errmsg(de));
1342 if (dwarf_linesrc(lbuf[i], &sfile, &de)) {
1343 warnx("dwarf_linesrc: %s", dwarf_errmsg(de));
1346 if ((lie = malloc(sizeof(*lie))) == NULL) {
1350 lie->addr = lineaddr;
1352 lie->file = strdup(sfile);
1353 if (lie->file == NULL) {
1358 SLIST_INSERT_HEAD(line_info, lie, entries);
1362 /* Retrieve line number information from DIEs. */
1363 search_line_attr(dbg, func_info, var_info, die, src_files, filecount);
1366 (void) dwarf_finish(dbg, &de);
1370 p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx,
1371 type_table, (void *) sec_table, shnum);
1373 if (p_data.list_num == 0)
1376 p_data.headp = &list_head;
1377 p_data.sh_num = shnum;
1378 p_data.t_table = type_table;
1379 p_data.s_table = (void *) sec_table;
1380 p_data.filename = filename;
1381 p_data.objname = objname;
1383 sym_list_print(&p_data, func_info, var_info, line_info);
1386 if (nm_opts.debug_line) {
1387 if (func_info != NULL) {
1388 while (!SLIST_EMPTY(func_info)) {
1389 func = SLIST_FIRST(func_info);
1390 SLIST_REMOVE_HEAD(func_info, entries);
1398 if (var_info != NULL) {
1399 while (!SLIST_EMPTY(var_info)) {
1400 var = SLIST_FIRST(var_info);
1401 SLIST_REMOVE_HEAD(var_info, entries);
1409 if (line_info != NULL) {
1410 while (!SLIST_EMPTY(line_info)) {
1411 lie = SLIST_FIRST(line_info);
1412 SLIST_REMOVE_HEAD(line_info, entries);
1421 if (sec_table != NULL)
1422 for (i = 0; i < shnum; ++i)
1427 sym_list_dest(&list_head);
1435 read_object(const char *filename)
1442 assert(filename != NULL && "filename is null");
1444 if ((fd = open(filename, O_RDONLY)) == -1) {
1445 warn("'%s'", filename);
1449 elf_cmd = ELF_C_READ;
1450 if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) {
1451 if ((e_err = elf_errno()) != 0)
1452 warnx("elf_begin error: %s", elf_errmsg(e_err));
1454 warnx("elf_begin error");
1459 assert(arf != NULL && "arf is null.");
1462 if ((kind = elf_kind(arf)) == ELF_K_NONE) {
1463 warnx("%s: File format not recognized", filename);
1468 if (kind == ELF_K_AR) {
1469 if (nm_opts.print_name == PRINT_NAME_MULTI &&
1470 nm_opts.elem_print_fn == sym_elem_print_all)
1471 printf("\n%s:\n", filename);
1472 if (nm_opts.print_armap == true)
1473 print_ar_index(fd, arf);
1476 while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) {
1477 rtn |= read_elf(elf, filename, kind);
1480 * If file is not archive, elf_next return ELF_C_NULL and
1483 elf_cmd = elf_next(elf);
1494 read_files(int argc, char **argv)
1498 if (argc < 0 || argv == NULL)
1502 rtn |= read_object(nm_info.def_filename);
1504 if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1)
1505 nm_opts.print_name = PRINT_NAME_MULTI;
1507 rtn |= read_object(*argv);
1517 print_lineno(struct sym_entry *ep, struct func_info_head *func_info,
1518 struct var_info_head *var_info, struct line_info_head *line_info)
1520 struct func_info_entry *func;
1521 struct var_info_entry *var;
1522 struct line_info_entry *lie;
1524 /* For function symbol, search the function line information list. */
1525 if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) {
1526 SLIST_FOREACH(func, func_info, entries) {
1527 if (!strcmp(ep->name, func->name) &&
1528 ep->sym->st_value >= func->lowpc &&
1529 ep->sym->st_value < func->highpc) {
1530 printf("\t%s:%" PRIu64, func->file, func->line);
1536 /* For variable symbol, search the variable line information list. */
1537 if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) {
1538 SLIST_FOREACH(var, var_info, entries) {
1539 if (!strcmp(ep->name, var->name) &&
1540 ep->sym->st_value == var->addr) {
1541 printf("\t%s:%" PRIu64, var->file, var->line);
1547 /* Otherwise search line number information the .debug_line section. */
1548 if (line_info != NULL) {
1549 SLIST_FOREACH(lie, line_info, entries) {
1550 if (ep->sym->st_value == lie->addr) {
1551 printf("\t%s:%" PRIu64, lie->file, lie->line);
1559 set_opt_value_print_fn(enum radix t)
1564 nm_opts.value_print_fn = &sym_value_oct_print;
1565 nm_opts.size_print_fn = &sym_size_oct_print;
1569 nm_opts.value_print_fn = &sym_value_dec_print;
1570 nm_opts.size_print_fn = &sym_size_dec_print;
1575 nm_opts.value_print_fn = &sym_value_hex_print;
1576 nm_opts.size_print_fn = &sym_size_hex_print;
1579 assert(nm_opts.value_print_fn != NULL &&
1580 "nm_opts.value_print_fn is null");
1584 sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym,
1588 if (sec == NULL || sym == NULL || name == NULL ||
1589 nm_opts.value_print_fn == NULL)
1592 if (IS_UNDEF_SYM_TYPE(type)) {
1593 if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32)
1596 printf("%-16s", "");
1598 switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) +
1599 nm_opts.print_size) {
1601 if (sym->st_size != 0) {
1602 nm_opts.value_print_fn(sym);
1604 nm_opts.size_print_fn(sym);
1609 if (sym->st_size != 0)
1610 nm_opts.size_print_fn(sym);
1614 nm_opts.value_print_fn(sym);
1615 if (sym->st_size != 0) {
1617 nm_opts.size_print_fn(sym);
1623 nm_opts.value_print_fn(sym);
1627 printf(" %c ", type);
1628 PRINT_DEMANGLED_NAME("%s", name);
1632 sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym,
1636 if (sec == NULL || sym == NULL || name == NULL ||
1637 nm_opts.value_print_fn == NULL)
1640 PRINT_DEMANGLED_NAME("%s", name);
1641 printf(" %c ", type);
1642 if (!IS_UNDEF_SYM_TYPE(type)) {
1643 nm_opts.value_print_fn(sym);
1645 if (sym->st_size != 0)
1646 nm_opts.size_print_fn(sym);
1652 sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym,
1656 if (sec == NULL || sym == NULL || name == NULL ||
1657 nm_opts.value_print_fn == NULL)
1660 PRINT_DEMANGLED_NAME("%-20s|", name);
1661 if (IS_UNDEF_SYM_TYPE(type))
1664 nm_opts.value_print_fn(sym);
1666 printf("| %c |", type);
1668 switch (sym->st_info & 0xf) {
1670 printf("%18s|", "OBJECT");
1674 printf("%18s|", "FUNC");
1678 printf("%18s|", "SECTION");
1682 printf("%18s|", "FILE");
1686 printf("%18s|", "LOPROC");
1690 printf("%18s|", "HIPROC");
1695 printf("%18s|", "NOTYPE");
1698 if (sym->st_size != 0)
1699 nm_opts.size_print_fn(sym);
1703 printf("| |%s", sec);
1707 sym_elem_def(char type, const GElf_Sym *sym, const char *name)
1710 assert(IS_SYM_TYPE((unsigned char) type));
1715 return (!IS_UNDEF_SYM_TYPE((unsigned char) type));
1719 sym_elem_global(char type, const GElf_Sym *sym, const char *name)
1722 assert(IS_SYM_TYPE((unsigned char) type));
1727 /* weak symbols resemble global. */
1728 return (isupper((unsigned char) type) || type == 'w');
1732 sym_elem_global_static(char type, const GElf_Sym *sym, const char *name)
1736 assert(sym != NULL);
1741 info = sym->st_info >> 4;
1743 return (info == STB_LOCAL ||
1744 info == STB_GLOBAL ||
1749 sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name)
1752 assert(sym != NULL);
1757 if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE)
1759 if (sym->st_name == 0)
1766 sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name)
1769 assert(sym != NULL);
1774 return (sym->st_size > 0);
1778 sym_elem_undef(char type, const GElf_Sym *sym, const char *name)
1781 assert(IS_SYM_TYPE((unsigned char) type));
1786 return (IS_UNDEF_SYM_TYPE((unsigned char) type));
1790 sym_list_dest(struct sym_head *headp)
1792 struct sym_entry *ep, *ep_n;
1797 ep = STAILQ_FIRST(headp);
1798 while (ep != NULL) {
1799 ep_n = STAILQ_NEXT(ep, sym_entries);
1808 sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym)
1810 struct sym_entry *e;
1812 if (headp == NULL || name == NULL || sym == NULL)
1814 if ((e = malloc(sizeof(struct sym_entry))) == NULL) {
1818 if ((e->name = strdup(name)) == NULL) {
1823 if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) {
1830 memcpy(e->sym, sym, sizeof(GElf_Sym));
1832 /* Display size instead of value for common symbol. */
1833 if (sym->st_shndx == SHN_COMMON)
1834 e->sym->st_value = sym->st_size;
1836 STAILQ_INSERT_TAIL(headp, e, sym_entries);
1841 /* If file has not .debug_info, line_info will be NULL */
1843 sym_list_print(struct sym_print_data *p, struct func_info_head *func_info,
1844 struct var_info_head *var_info, struct line_info_head *line_info)
1846 struct sym_entry *e_v;
1850 if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1852 if ((e_v = sym_list_sort(p)) == NULL)
1854 if (nm_opts.sort_reverse == false)
1855 for (si = 0; si != p->list_num; ++si)
1856 sym_list_print_each(&e_v[si], p, func_info, var_info,
1859 for (i = p->list_num - 1; i != -1; --i)
1860 sym_list_print_each(&e_v[i], p, func_info, var_info,
1866 /* If file has not .debug_info, line_info will be NULL */
1868 sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p,
1869 struct func_info_head *func_info, struct var_info_head *var_info,
1870 struct line_info_head *line_info)
1875 if (ep == NULL || CHECK_SYM_PRINT_DATA(p))
1878 assert(ep->name != NULL);
1879 assert(ep->sym != NULL);
1881 type = get_sym_type(ep->sym, p->t_table);
1883 if (nm_opts.print_name == PRINT_NAME_FULL) {
1884 printf("%s", p->filename);
1885 if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) {
1886 if (p->objname != NULL)
1887 printf("[%s]", p->objname);
1890 if (p->objname != NULL)
1891 printf(":%s", p->objname);
1896 switch (ep->sym->st_shndx) {
1898 /* LOPROC or LORESERVE */
1917 /* HIRESERVE or XINDEX */
1918 sec = "*HIRESERVE*";
1921 if (ep->sym->st_shndx > p->sh_num)
1923 sec = p->s_table[ep->sym->st_shndx];
1927 nm_opts.elem_print_fn(type, sec, ep->sym, ep->name);
1929 if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type))
1930 print_lineno(ep, func_info, var_info, line_info);
1935 static struct sym_entry *
1936 sym_list_sort(struct sym_print_data *p)
1938 struct sym_entry *ep, *e_v;
1941 if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1944 if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) {
1950 STAILQ_FOREACH(ep, p->headp, sym_entries) {
1951 if (ep->name != NULL && ep->sym != NULL) {
1952 e_v[idx].name = ep->name;
1953 e_v[idx].sym = ep->sym;
1958 assert((size_t)idx == p->list_num);
1960 if (nm_opts.sort_fn != &cmp_none) {
1962 assert(nm_print_data != NULL);
1963 qsort(e_v, p->list_num, sizeof(struct sym_entry),
1971 sym_size_oct_print(const GElf_Sym *sym)
1974 assert(sym != NULL && "sym is null");
1975 printf("%016" PRIo64, sym->st_size);
1979 sym_size_hex_print(const GElf_Sym *sym)
1982 assert(sym != NULL && "sym is null");
1983 if (nm_elfclass == ELFCLASS32)
1984 printf("%08" PRIx64, sym->st_size);
1986 printf("%016" PRIx64, sym->st_size);
1990 sym_size_dec_print(const GElf_Sym *sym)
1993 assert(sym != NULL && "sym is null");
1994 printf("%016" PRId64, sym->st_size);
1998 sym_value_oct_print(const GElf_Sym *sym)
2001 assert(sym != NULL && "sym is null");
2002 printf("%016" PRIo64, sym->st_value);
2006 sym_value_hex_print(const GElf_Sym *sym)
2009 assert(sym != NULL && "sym is null");
2010 if (nm_elfclass == ELFCLASS32)
2011 printf("%08" PRIx64, sym->st_value);
2013 printf("%016" PRIx64, sym->st_value);
2017 sym_value_dec_print(const GElf_Sym *sym)
2020 assert(sym != NULL && "sym is null");
2021 printf("%016" PRId64, sym->st_value);
2028 printf("Usage: %s [options] file ...\
2029 \n Display symbolic information in file.\n\
2031 \n -A, --print-file-name Write the full pathname or library name of an\
2032 \n object on each line.\
2033 \n -a, --debug-syms Display all symbols include debugger-only\
2034 \n symbols.", nm_info.name);
2036 \n -B Equivalent to specifying \"--format=bsd\".\
2037 \n -C, --demangle[=style] Decode low-level symbol names.\
2038 \n --no-demangle Do not demangle low-level symbol names.\
2039 \n -D, --dynamic Display only dynamic symbols.\
2040 \n -e Display only global and static symbols.");
2042 \n -f Produce full output (default).\
2043 \n --format=format Display output in specific format. Allowed\
2044 \n formats are: \"bsd\", \"posix\" and \"sysv\".\
2045 \n -g Display only global symbol information.\
2046 \n -h, --help Show this help message.\
2047 \n -l, --line-numbers Display filename and linenumber using\
2048 \n debugging information.\
2049 \n -n, --numeric-sort Sort symbols numerically by value.");
2051 \n -o Write numeric values in octal. Equivalent to\
2052 \n specifying \"-t o\".\
2053 \n -p, --no-sort Do not sort symbols.\
2054 \n -P Write information in a portable output format.\
2055 \n Equivalent to specifying \"--format=posix\".\
2056 \n -r, --reverse-sort Reverse the order of the sort.\
2057 \n -S, --print-size Print symbol sizes instead values.\
2058 \n -s, --print-armap Include an index of archive members.\
2059 \n --size-sort Sort symbols by size.");
2061 \n -t, --radix=format Write each numeric value in the specified\
2065 \n x In hexadecimal.");
2067 \n -u, --undefined-only Display only undefined symbols.\
2068 \n --defined-only Display only defined symbols.\
2069 \n -V, --version Show the version identifier for %s.\
2070 \n -v Sort output by value.\
2071 \n -x Write numeric values in hexadecimal.\
2072 \n Equivalent to specifying \"-t x\".",
2075 \n The default options are: output in bsd format, use a hexadecimal radix,\
2076 \n sort by symbol name, do not demangle names.\n");
2082 * Display symbolic information in file.
2083 * Return 0 at success, >0 at failed.
2086 main(int argc, char **argv)
2091 get_opt(argc, argv);
2092 rtn = read_files(argc - optind, argv + optind);