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 3145 2015-02-15 18:04:37Z emaste $");
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 { "extern-only", no_argument, NULL, 'g' },
252 { "format", required_argument, NULL, 'F' },
253 { "help", no_argument, NULL, 'h' },
254 { "line-numbers", no_argument, NULL, 'l' },
255 { "no-demangle", no_argument, &nm_opts.no_demangle,
257 { "no-sort", no_argument, NULL, 'p' },
258 { "numeric-sort", no_argument, NULL, 'v' },
259 { "print-armap", no_argument, NULL, 's' },
260 { "print-file-name", no_argument, NULL, 'A' },
261 { "print-size", no_argument, NULL, 'S' },
262 { "radix", required_argument, NULL, 't' },
263 { "reverse-sort", no_argument, NULL, 'r' },
264 { "size-sort", no_argument, &nm_opts.sort_size, 1},
265 { "undefined-only", no_argument, NULL, 'u' },
266 { "version", no_argument, NULL, 'V' },
270 #if defined(ELFTC_NEED_BYTEORDER_EXTENSIONS)
271 static __inline uint32_t
272 be32dec(const void *pp)
274 unsigned char const *p = (unsigned char const *)pp;
276 return ((p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]);
279 static __inline uint32_t
280 le32dec(const void *pp)
282 unsigned char const *p = (unsigned char const *)pp;
284 return ((p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
287 static __inline uint64_t
288 be64dec(const void *pp)
290 unsigned char const *p = (unsigned char const *)pp;
292 return (((uint64_t)be32dec(p) << 32) | be32dec(p + 4));
295 static __inline uint64_t
296 le64dec(const void *pp)
298 unsigned char const *p = (unsigned char const *)pp;
300 return (((uint64_t)le32dec(p + 4) << 32) | le32dec(p));
305 cmp_name(const void *l, const void *r)
310 assert(((const struct sym_entry *)l)->name != NULL);
311 assert(((const struct sym_entry *)r)->name != NULL);
313 return (strcmp(((const struct sym_entry *)l)->name,
314 ((const struct sym_entry *)r)->name));
318 cmp_none(const void *l, const void *r)
327 /* Size comparison. If l and r have same size, compare their name. */
329 cmp_size(const void *lp, const void *rp)
331 const struct sym_entry *l, *r;
337 assert(l->name != NULL);
338 assert(l->sym != NULL);
340 assert(r->name != NULL);
341 assert(r->sym != NULL);
343 if (l->sym->st_size == r->sym->st_size)
344 return (strcmp(l->name, r->name));
346 return (l->sym->st_size - r->sym->st_size);
349 /* Value comparison. Undefined symbols come first. */
351 cmp_value(const void *lp, const void *rp)
353 const struct sym_entry *l, *r;
355 int l_is_undef, r_is_undef;
360 assert(nm_print_data != NULL);
361 ttable = nm_print_data->t_table;
364 assert(l->name != NULL);
365 assert(l->sym != NULL);
367 assert(r->name != NULL);
368 assert(r->sym != NULL);
369 assert(ttable != NULL);
371 l_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(l->sym, ttable)) ? 1 : 0;
372 r_is_undef = IS_UNDEF_SYM_TYPE(get_sym_type(r->sym, ttable)) ? 1 : 0;
374 assert(l_is_undef + r_is_undef >= 0);
375 assert(l_is_undef + r_is_undef <= 2);
377 switch (l_is_undef + r_is_undef) {
380 if (l->sym->st_value == r->sym->st_value)
381 return (strcmp(l->name, r->name));
382 return (l->sym->st_value - r->sym->st_value);
385 return (l_is_undef == 0 ? 1 : -1);
388 return (strcmp(l->name, r->name));
392 return (l->sym->st_value - r->sym->st_value);
398 struct filter_entry *e;
400 while (!SLIST_EMPTY(&nm_out_filter)) {
401 e = SLIST_FIRST(&nm_out_filter);
402 SLIST_REMOVE_HEAD(&nm_out_filter, filter_entries);
408 filter_insert(fn_filter filter_fn)
410 struct filter_entry *e;
412 assert(filter_fn != NULL);
414 if ((e = malloc(sizeof(struct filter_entry))) == NULL) {
419 SLIST_INSERT_HEAD(&nm_out_filter, e, filter_entries);
425 parse_demangle_option(const char *opt)
429 return (ELFTC_DEM_UNKNOWN);
430 else if (!strncasecmp(opt, "gnu-v2", 6))
431 return (ELFTC_DEM_GNU2);
432 else if (!strncasecmp(opt, "gnu-v3", 6))
433 return (ELFTC_DEM_GNU3);
434 else if (!strncasecmp(opt, "arm", 3))
435 return (ELFTC_DEM_ARM);
437 errx(EXIT_FAILURE, "unknown demangling style '%s'", opt);
444 get_opt(int argc, char **argv)
447 bool is_posix, oflag;
449 if (argc <= 0 || argv == NULL)
452 oflag = is_posix = false;
453 nm_opts.t = RADIX_HEX;
454 while ((ch = getopt_long(argc, argv, "ABCDF:PSVaefghlnoprst:uvx",
455 nm_longopts, NULL)) != -1) {
458 nm_opts.print_name = PRINT_NAME_FULL;
461 nm_opts.elem_print_fn = &sym_elem_print_all;
464 nm_opts.demangle_type = parse_demangle_option(optarg);
467 nm_opts.print_symbol = PRINT_SYM_DYN;
470 /* sysv, bsd, posix */
474 nm_opts.elem_print_fn = &sym_elem_print_all;
479 nm_opts.elem_print_fn =
480 &sym_elem_print_all_portable;
484 nm_opts.elem_print_fn =
485 &sym_elem_print_all_sysv;
488 warnx("%s: Invalid format", optarg);
495 nm_opts.elem_print_fn = &sym_elem_print_all_portable;
498 nm_opts.print_size = 1;
504 nm_opts.print_debug = true;
507 filter_insert(sym_elem_global_static);
512 filter_insert(sym_elem_global);
518 nm_opts.debug_line = true;
522 nm_opts.sort_fn = &cmp_value;
528 nm_opts.sort_fn = &cmp_none;
531 nm_opts.sort_reverse = true;
534 nm_opts.print_armap = true;
537 /* t require always argument to getopt_long */
540 nm_opts.t = RADIX_DEC;
543 nm_opts.t = RADIX_OCT;
546 nm_opts.t = RADIX_HEX;
549 warnx("%s: Invalid radix", optarg);
554 filter_insert(sym_elem_undef);
555 nm_opts.undef_only = true;
557 /* case 'v': see case 'n' above. */
559 nm_opts.t = RADIX_HEX;
562 if (nm_opts.sort_size != 0) {
563 nm_opts.sort_fn = &cmp_size;
564 filter_insert(sym_elem_def);
565 filter_insert(sym_elem_nonzero_size);
567 if (nm_opts.def_only != 0)
568 filter_insert(sym_elem_def);
569 if (nm_opts.no_demangle != 0)
570 nm_opts.demangle_type = -1;
578 * In POSIX mode, the '-o' option controls the output radix.
579 * In non-POSIX mode, the option is a synonym for the '-A' and
580 * '--print-file-name' options.
584 nm_opts.t = RADIX_OCT;
586 nm_opts.print_name = PRINT_NAME_FULL;
589 assert(nm_opts.sort_fn != NULL && "nm_opts.sort_fn is null");
590 assert(nm_opts.elem_print_fn != NULL &&
591 "nm_opts.elem_print_fn is null");
592 assert(nm_opts.value_print_fn != NULL &&
593 "nm_opts.value_print_fn is null");
595 set_opt_value_print_fn(nm_opts.t);
597 if (nm_opts.undef_only == true) {
598 if (nm_opts.sort_fn == &cmp_size)
600 "--size-sort with -u is meaningless");
601 if (nm_opts.def_only != 0)
603 "-u with --defined-only is meaningless");
605 if (nm_opts.print_debug == false)
606 filter_insert(sym_elem_nondebug);
607 if (nm_opts.sort_reverse == true && nm_opts.sort_fn == cmp_none)
608 nm_opts.sort_reverse = false;
612 * Get symbol information from elf.
615 get_sym(Elf *elf, struct sym_head *headp, int shnum, size_t dynndx,
616 size_t strndx, const char *type_table, const char **sec_table,
623 struct filter_entry *fep;
626 const char *sym_name;
632 assert(headp != NULL);
635 for (i = 1; i < shnum; i++) {
636 if ((scn = elf_getscn(elf, i)) == NULL) {
637 warnx("elf_getscn failed: %s", elf_errmsg(-1));
640 if (gelf_getshdr(scn, &shdr) != &shdr) {
641 warnx("gelf_getshdr failed: %s", elf_errmsg(-1));
644 if (shdr.sh_type == SHT_SYMTAB) {
645 if (nm_opts.print_symbol != PRINT_SYM_SYM)
647 } else if (shdr.sh_type == SHT_DYNSYM) {
648 if (nm_opts.print_symbol != PRINT_SYM_DYN)
653 ndx = shdr.sh_type == SHT_DYNSYM ? dynndx : strndx;
656 while ((data = elf_getdata(scn, data)) != NULL) {
658 while (gelf_getsym(data, j++, &sym) != NULL) {
659 sym_name = get_sym_name(elf, &sym, ndx,
660 sec_table, sec_table_size);
662 type = get_sym_type(&sym, type_table);
663 SLIST_FOREACH(fep, &nm_out_filter,
665 if (!fep->fn(type, &sym, sym_name)) {
670 if (filter == false) {
671 if (sym_list_insert(headp, sym_name,
684 get_sym_name(Elf *elf, const GElf_Sym *sym, size_t ndx, const char **sec_table,
687 const char *sym_name;
691 /* Show section name as symbol name for STT_SECTION symbols. */
692 if (GELF_ST_TYPE(sym->st_info) == STT_SECTION) {
693 if (sec_table != NULL && sym->st_shndx < sec_table_size)
694 sym_name = sec_table[sym->st_shndx];
696 sym_name = elf_strptr(elf, ndx, sym->st_name);
698 if (sym_name == NULL)
705 get_sym_type(const GElf_Sym *sym, const char *type_table)
709 if (sym == NULL || type_table == NULL)
712 is_local = sym->st_info >> 4 == STB_LOCAL;
714 if (sym->st_shndx == SHN_ABS) /* absolute */
715 return (is_local ? 'a' : 'A');
717 if (sym->st_shndx == SHN_COMMON) /* common */
720 if ((sym->st_info) >> 4 == STB_WEAK) { /* weak */
721 if ((sym->st_info & 0xf) == STT_OBJECT)
722 return (sym->st_shndx == SHN_UNDEF ? 'v' : 'V');
724 return (sym->st_shndx == SHN_UNDEF ? 'w' : 'W');
727 if (sym->st_shndx == SHN_UNDEF) /* undefined */
730 return (is_local == true && type_table[sym->st_shndx] != 'N' ?
731 tolower((unsigned char) type_table[sym->st_shndx]) :
732 type_table[sym->st_shndx]);
746 if (elf_version(EV_CURRENT) == EV_NONE)
747 errx(EXIT_FAILURE, "elf_version error");
749 nm_info.name = ELFTC_GETPROGNAME();
750 nm_info.def_filename = "a.out";
751 nm_opts.print_symbol = PRINT_SYM_SYM;
752 nm_opts.print_name = PRINT_NAME_NONE;
753 nm_opts.demangle_type = -1;
754 nm_opts.print_debug = false;
755 nm_opts.print_armap = false;
756 nm_opts.print_size = 0;
757 nm_opts.debug_line = false;
758 nm_opts.def_only = 0;
759 nm_opts.undef_only = false;
760 nm_opts.sort_size = 0;
761 nm_opts.sort_reverse = false;
762 nm_opts.no_demangle = 0;
763 nm_opts.sort_fn = &cmp_name;
764 nm_opts.elem_print_fn = &sym_elem_print_all;
765 nm_opts.value_print_fn = &sym_value_dec_print;
766 nm_opts.size_print_fn = &sym_size_dec_print;
767 SLIST_INIT(&nm_out_filter);
771 is_sec_data(GElf_Shdr *s)
774 assert(s != NULL && "shdr is NULL");
776 return (((s->sh_flags & SHF_ALLOC) != 0) && s->sh_type != SHT_NOBITS);
780 is_sec_debug(const char *shname)
782 const char *dbg_sec[] = {
793 assert(shname != NULL && "shname is NULL");
795 for (p = dbg_sec; *p; p++) {
796 if (!strncmp(shname, *p, strlen(*p)))
804 is_sec_nobits(GElf_Shdr *s)
807 assert(s != NULL && "shdr is NULL");
809 return (s->sh_type == SHT_NOBITS);
813 is_sec_readonly(GElf_Shdr *s)
816 assert(s != NULL && "shdr is NULL");
818 return ((s->sh_flags & SHF_WRITE) == 0);
822 is_sec_text(GElf_Shdr *s)
825 assert(s != NULL && "shdr is NULL");
827 return ((s->sh_flags & SHF_EXECINSTR) != 0);
831 print_ar_index(int fd, Elf *arf)
843 if ((arsym = elf_getarsym(arf, &arsym_size)) == NULL)
846 printf("\nArchive index:\n");
848 start = arsym->as_off;
850 while (arsym_size > 1) {
851 if (elf_rand(arf, arsym->as_off) == arsym->as_off &&
852 (elf = elf_begin(fd, cmd, arf)) != NULL) {
853 if ((arhdr = elf_getarhdr(elf)) != NULL)
854 printf("%s in %s\n", arsym->as_name,
855 arhdr->ar_name != NULL ?
856 arhdr->ar_name : arhdr->ar_rawname);
863 elf_rand(arf, start);
866 #define DEMANGLED_BUFFER_SIZE (8 * 1024)
867 #define PRINT_DEMANGLED_NAME(FORMAT, NAME) do { \
868 char _demangled[DEMANGLED_BUFFER_SIZE]; \
869 if (nm_opts.demangle_type < 0 || \
870 elftc_demangle((NAME), _demangled, sizeof(_demangled), \
871 nm_opts.demangle_type) < 0) \
872 printf((FORMAT), (NAME)); \
874 printf((FORMAT), _demangled); \
878 print_header(const char *file, const char *obj)
884 if (nm_opts.elem_print_fn == &sym_elem_print_all_sysv) {
885 printf("\n\n%s from %s",
886 nm_opts.undef_only == false ? "Symbols" :
887 "Undefined symbols", file);
893 Name Value Class Type Size Line Section\n\n");
895 /* archive file without -A option and POSIX */
896 if (nm_opts.print_name != PRINT_NAME_FULL && obj != NULL) {
897 if (nm_opts.elem_print_fn ==
898 sym_elem_print_all_portable)
899 printf("%s[%s]:\n", file, obj);
900 else if (nm_opts.elem_print_fn == sym_elem_print_all)
901 printf("\n%s:\n", obj);
902 /* multiple files(not archive) without -A option */
903 } else if (nm_opts.print_name == PRINT_NAME_MULTI) {
904 if (nm_opts.elem_print_fn == sym_elem_print_all)
906 printf("%s:\n", file);
915 (void) printf("%s (%s)\n", nm_info.name, elftc_version());
920 get_block_value(Dwarf_Debug dbg, Dwarf_Block *block)
926 if (dwarf_get_elf(dbg, &elf, &de) != DW_DLV_OK) {
927 warnx("dwarf_get_elf failed: %s", dwarf_errmsg(de));
931 if (gelf_getehdr(elf, &eh) != &eh) {
932 warnx("gelf_getehdr failed: %s", elf_errmsg(-1));
936 if (block->bl_len == 5) {
937 if (eh.e_ident[EI_DATA] == ELFDATA2LSB)
938 return (le32dec((uint8_t *) block->bl_data + 1));
940 return (be32dec((uint8_t *) block->bl_data + 1));
941 } else if (block->bl_len == 9) {
942 if (eh.e_ident[EI_DATA] == ELFDATA2LSB)
943 return (le64dec((uint8_t *) block->bl_data + 1));
945 return (be64dec((uint8_t *) block->bl_data + 1));
952 search_line_attr(Dwarf_Debug dbg, struct func_info_head *func_info,
953 struct var_info_head *var_info, Dwarf_Die die, char **src_files,
954 Dwarf_Signed filecount)
957 Dwarf_Unsigned udata;
963 struct func_info_entry *func;
964 struct var_info_entry *var;
968 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
969 warnx("dwarf_tag failed: %s", dwarf_errmsg(de));
973 /* We're interested in DIEs which define functions or variables. */
974 if (tag != DW_TAG_subprogram && tag != DW_TAG_entry_point &&
975 tag != DW_TAG_inlined_subroutine && tag != DW_TAG_variable)
978 if (tag == DW_TAG_variable) {
980 /* Ignore "artificial" variable. */
981 if (dwarf_attrval_flag(die, DW_AT_artificial, &flag, &de) ==
985 /* Ignore pure declaration. */
986 if (dwarf_attrval_flag(die, DW_AT_declaration, &flag, &de) ==
990 /* Ignore stack varaibles. */
991 if (dwarf_attrval_flag(die, DW_AT_external, &flag, &de) !=
995 if ((var = calloc(1, sizeof(*var))) == NULL) {
996 warn("calloc failed");
1000 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata,
1001 &de) == DW_DLV_OK && udata > 0 &&
1002 (Dwarf_Signed) (udata - 1) < filecount) {
1003 var->file = strdup(src_files[udata - 1]);
1004 if (var->file == NULL) {
1011 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) ==
1015 if (dwarf_attrval_string(die, DW_AT_name, &str, &de) ==
1017 var->name = strdup(str);
1018 if (var->name == NULL) {
1027 if (dwarf_attr(die, DW_AT_location, &at, &de) == DW_DLV_OK &&
1028 dwarf_formblock(at, &block, &de) == DW_DLV_OK) {
1030 * Since we ignored stack variables, the rest are the
1031 * external varaibles which should always use DW_OP_addr
1032 * operator for DW_AT_location value.
1034 if (*((uint8_t *)block->bl_data) == DW_OP_addr)
1035 var->addr = get_block_value(dbg, block);
1038 SLIST_INSERT_HEAD(var_info, var, entries);
1042 if ((func = calloc(1, sizeof(*func))) == NULL) {
1043 warn("calloc failed");
1048 * Note that dwarf_attrval_unsigned() handles DW_AT_abstract_origin
1049 * internally, so it can retrieve DW_AT_decl_file/DW_AT_decl_line
1050 * attributes for inlined functions as well.
1052 if (dwarf_attrval_unsigned(die, DW_AT_decl_file, &udata,
1053 &de) == DW_DLV_OK && udata > 0 &&
1054 (Dwarf_Signed) (udata - 1) < filecount) {
1055 func->file = strdup(src_files[udata - 1]);
1056 if (func->file == NULL) {
1063 if (dwarf_attrval_unsigned(die, DW_AT_decl_line, &udata, &de) ==
1067 if (dwarf_attrval_string(die, DW_AT_name, &str, &de) ==
1069 func->name = strdup(str);
1070 if (func->name == NULL) {
1079 if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &udata, &de) ==
1081 func->lowpc = udata;
1082 if (dwarf_attrval_unsigned(die, DW_AT_high_pc, &udata, &de) ==
1084 func->highpc = udata;
1086 SLIST_INSERT_HEAD(func_info, func, entries);
1091 /* Search children. */
1092 ret = dwarf_child(die, &ret_die, &de);
1093 if (ret == DW_DLV_ERROR)
1094 warnx("dwarf_child: %s", dwarf_errmsg(de));
1095 else if (ret == DW_DLV_OK)
1096 search_line_attr(dbg, func_info, var_info, ret_die, src_files,
1099 /* Search sibling. */
1100 ret = dwarf_siblingof(dbg, die, &ret_die, &de);
1101 if (ret == DW_DLV_ERROR)
1102 warnx("dwarf_siblingof: %s", dwarf_errmsg(de));
1103 else if (ret == DW_DLV_OK)
1104 search_line_attr(dbg, func_info, var_info, ret_die, src_files,
1107 dwarf_dealloc(dbg, die, DW_DLA_DIE);
1111 * Read elf file and collect symbol information, sort them, print.
1112 * Return 1 at failed, 0 at success.
1115 read_elf(Elf *elf, const char *filename, Elf_Kind kind)
1126 Dwarf_Unsigned lineno;
1127 Dwarf_Signed lcount, filecount;
1128 Dwarf_Addr lineaddr;
1129 struct sym_print_data p_data;
1130 struct sym_head list_head;
1131 struct line_info_head *line_info;
1132 struct func_info_head *func_info;
1133 struct var_info_head *var_info;
1134 struct line_info_entry *lie;
1135 struct func_info_entry *func;
1136 struct var_info_entry *var;
1137 const char *shname, *objname;
1138 char *type_table, **sec_table, *sfile, **src_files;
1139 size_t shstrndx, shnum, dynndx, strndx;
1140 int ret, rtn, e_err;
1142 #define OBJNAME (objname == NULL ? filename : objname)
1144 assert(filename != NULL && "filename is null");
1146 STAILQ_INIT(&list_head);
1157 nm_elfclass = gelf_getclass(elf);
1159 if (kind == ELF_K_AR) {
1160 if ((arhdr = elf_getarhdr(elf)) == NULL)
1162 objname = arhdr->ar_name != NULL ? arhdr->ar_name :
1165 if (!elf_getshnum(elf, &shnum)) {
1166 if ((e_err = elf_errno()) != 0)
1167 warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1169 warnx("%s: cannot get section number", OBJNAME);
1174 warnx("%s: has no section", OBJNAME);
1178 if (!elf_getshstrndx(elf, &shstrndx)) {
1179 warnx("%s: cannot get str index", OBJNAME);
1183 /* type_table for type determine */
1184 if ((type_table = malloc(sizeof(char) * shnum)) == NULL) {
1185 warn("%s: malloc", OBJNAME);
1189 /* sec_table for section name to display in sysv format */
1190 if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) {
1191 warn("%s: calloc", OBJNAME);
1196 type_table[0] = 'U';
1197 if ((sec_table[0] = strdup("*UND*")) == NULL) {
1202 for (i = 1; i < shnum; ++i) {
1203 type_table[i] = 'U';
1204 if ((scn = elf_getscn(elf, i)) == NULL) {
1205 if ((e_err = elf_errno()) != 0)
1206 warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1208 warnx("%s: cannot get section", OBJNAME);
1212 if (gelf_getshdr(scn, &shdr) == NULL)
1216 * Cannot test by type and attribute for dynstr, strtab
1218 shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name);
1219 if (shname != NULL) {
1220 if ((sec_table[i] = strdup(shname)) == NULL) {
1224 if (!strncmp(shname, ".dynstr", 7)) {
1225 dynndx = elf_ndxscn(scn);
1226 if (dynndx == SHN_UNDEF) {
1227 warnx("%s: elf_ndxscn failed: %s",
1228 OBJNAME, elf_errmsg(-1));
1232 if (!strncmp(shname, ".strtab", 7)) {
1233 strndx = elf_ndxscn(scn);
1234 if (strndx == SHN_UNDEF) {
1235 warnx("%s: elf_ndxscn failed: %s",
1236 OBJNAME, elf_errmsg(-1));
1241 sec_table[i] = strdup("*UND*");
1242 if (sec_table[i] == NULL) {
1249 if (is_sec_text(&shdr))
1250 type_table[i] = 'T';
1251 else if (is_sec_data(&shdr)) {
1252 if (is_sec_readonly(&shdr))
1253 type_table[i] = 'R';
1255 type_table[i] = 'D';
1256 } else if (is_sec_nobits(&shdr))
1257 type_table[i] = 'B';
1258 else if (is_sec_debug(shname))
1259 type_table[i] = 'N';
1260 else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr))
1261 type_table[i] = 'n';
1264 print_header(filename, objname);
1266 if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) ||
1267 (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) {
1268 warnx("%s: no symbols", OBJNAME);
1269 /* This is not an error case */
1273 STAILQ_INIT(&list_head);
1275 if (!nm_opts.debug_line)
1279 * Collect dwarf line number information.
1282 if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) !=
1284 warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de));
1288 line_info = malloc(sizeof(struct line_info_head));
1289 func_info = malloc(sizeof(struct func_info_head));
1290 var_info = malloc(sizeof(struct var_info_head));
1291 if (line_info == NULL || func_info == NULL || var_info == NULL) {
1293 (void) dwarf_finish(dbg, &de);
1296 SLIST_INIT(line_info);
1297 SLIST_INIT(func_info);
1298 SLIST_INIT(var_info);
1300 while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
1301 &de)) == DW_DLV_OK) {
1303 while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
1304 if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
1305 warnx("dwarf_tag failed: %s",
1309 /* XXX: What about DW_TAG_partial_unit? */
1310 if (tag == DW_TAG_compile_unit)
1314 warnx("could not find DW_TAG_compile_unit die");
1318 /* Retrieve source file list. */
1319 ret = dwarf_srcfiles(die, &src_files, &filecount, &de);
1320 if (ret == DW_DLV_ERROR)
1321 warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1322 if (ret != DW_DLV_OK)
1326 * Retrieve line number information from .debug_line section.
1329 ret = dwarf_srclines(die, &lbuf, &lcount, &de);
1330 if (ret == DW_DLV_ERROR)
1331 warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1332 if (ret != DW_DLV_OK)
1334 for (i = 0; (Dwarf_Signed) i < lcount; i++) {
1335 if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
1336 warnx("dwarf_lineaddr: %s", dwarf_errmsg(de));
1339 if (dwarf_lineno(lbuf[i], &lineno, &de)) {
1340 warnx("dwarf_lineno: %s", dwarf_errmsg(de));
1343 if (dwarf_linesrc(lbuf[i], &sfile, &de)) {
1344 warnx("dwarf_linesrc: %s", dwarf_errmsg(de));
1347 if ((lie = malloc(sizeof(*lie))) == NULL) {
1351 lie->addr = lineaddr;
1353 lie->file = strdup(sfile);
1354 if (lie->file == NULL) {
1359 SLIST_INSERT_HEAD(line_info, lie, entries);
1363 /* Retrieve line number information from DIEs. */
1364 search_line_attr(dbg, func_info, var_info, die, src_files, filecount);
1367 (void) dwarf_finish(dbg, &de);
1371 p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx,
1372 type_table, (void *) sec_table, shnum);
1374 if (p_data.list_num == 0)
1377 p_data.headp = &list_head;
1378 p_data.sh_num = shnum;
1379 p_data.t_table = type_table;
1380 p_data.s_table = (void *) sec_table;
1381 p_data.filename = filename;
1382 p_data.objname = objname;
1384 sym_list_print(&p_data, func_info, var_info, line_info);
1387 if (nm_opts.debug_line) {
1388 if (func_info != NULL) {
1389 while (!SLIST_EMPTY(func_info)) {
1390 func = SLIST_FIRST(func_info);
1391 SLIST_REMOVE_HEAD(func_info, entries);
1399 if (var_info != NULL) {
1400 while (!SLIST_EMPTY(var_info)) {
1401 var = SLIST_FIRST(var_info);
1402 SLIST_REMOVE_HEAD(var_info, entries);
1410 if (line_info != NULL) {
1411 while (!SLIST_EMPTY(line_info)) {
1412 lie = SLIST_FIRST(line_info);
1413 SLIST_REMOVE_HEAD(line_info, entries);
1422 if (sec_table != NULL)
1423 for (i = 0; i < shnum; ++i)
1428 sym_list_dest(&list_head);
1436 read_object(const char *filename)
1443 assert(filename != NULL && "filename is null");
1445 if ((fd = open(filename, O_RDONLY)) == -1) {
1446 warn("'%s'", filename);
1450 elf_cmd = ELF_C_READ;
1451 if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) {
1452 if ((e_err = elf_errno()) != 0)
1453 warnx("elf_begin error: %s", elf_errmsg(e_err));
1455 warnx("elf_begin error");
1460 assert(arf != NULL && "arf is null.");
1463 if ((kind = elf_kind(arf)) == ELF_K_NONE) {
1464 warnx("%s: File format not recognized", filename);
1469 if (kind == ELF_K_AR) {
1470 if (nm_opts.print_name == PRINT_NAME_MULTI &&
1471 nm_opts.elem_print_fn == sym_elem_print_all)
1472 printf("\n%s:\n", filename);
1473 if (nm_opts.print_armap == true)
1474 print_ar_index(fd, arf);
1477 while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) {
1478 rtn |= read_elf(elf, filename, kind);
1481 * If file is not archive, elf_next return ELF_C_NULL and
1484 elf_cmd = elf_next(elf);
1495 read_files(int argc, char **argv)
1499 if (argc < 0 || argv == NULL)
1503 rtn |= read_object(nm_info.def_filename);
1505 if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1)
1506 nm_opts.print_name = PRINT_NAME_MULTI;
1508 rtn |= read_object(*argv);
1518 print_lineno(struct sym_entry *ep, struct func_info_head *func_info,
1519 struct var_info_head *var_info, struct line_info_head *line_info)
1521 struct func_info_entry *func;
1522 struct var_info_entry *var;
1523 struct line_info_entry *lie;
1525 /* For function symbol, search the function line information list. */
1526 if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) {
1527 SLIST_FOREACH(func, func_info, entries) {
1528 if (!strcmp(ep->name, func->name) &&
1529 ep->sym->st_value >= func->lowpc &&
1530 ep->sym->st_value < func->highpc) {
1531 printf("\t%s:%" PRIu64, func->file, func->line);
1537 /* For variable symbol, search the variable line information list. */
1538 if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) {
1539 SLIST_FOREACH(var, var_info, entries) {
1540 if (!strcmp(ep->name, var->name) &&
1541 ep->sym->st_value == var->addr) {
1542 printf("\t%s:%" PRIu64, var->file, var->line);
1548 /* Otherwise search line number information the .debug_line section. */
1549 if (line_info != NULL) {
1550 SLIST_FOREACH(lie, line_info, entries) {
1551 if (ep->sym->st_value == lie->addr) {
1552 printf("\t%s:%" PRIu64, lie->file, lie->line);
1560 set_opt_value_print_fn(enum radix t)
1565 nm_opts.value_print_fn = &sym_value_oct_print;
1566 nm_opts.size_print_fn = &sym_size_oct_print;
1570 nm_opts.value_print_fn = &sym_value_dec_print;
1571 nm_opts.size_print_fn = &sym_size_dec_print;
1576 nm_opts.value_print_fn = &sym_value_hex_print;
1577 nm_opts.size_print_fn = &sym_size_hex_print;
1580 assert(nm_opts.value_print_fn != NULL &&
1581 "nm_opts.value_print_fn is null");
1585 sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym,
1589 if (sec == NULL || sym == NULL || name == NULL ||
1590 nm_opts.value_print_fn == NULL)
1593 if (IS_UNDEF_SYM_TYPE(type)) {
1594 if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32)
1597 printf("%-16s", "");
1599 switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) +
1600 nm_opts.print_size) {
1602 if (sym->st_size != 0) {
1603 nm_opts.value_print_fn(sym);
1605 nm_opts.size_print_fn(sym);
1610 if (sym->st_size != 0)
1611 nm_opts.size_print_fn(sym);
1615 nm_opts.value_print_fn(sym);
1616 if (sym->st_size != 0) {
1618 nm_opts.size_print_fn(sym);
1624 nm_opts.value_print_fn(sym);
1628 printf(" %c ", type);
1629 PRINT_DEMANGLED_NAME("%s", name);
1633 sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym,
1637 if (sec == NULL || sym == NULL || name == NULL ||
1638 nm_opts.value_print_fn == NULL)
1641 PRINT_DEMANGLED_NAME("%s", name);
1642 printf(" %c ", type);
1643 if (!IS_UNDEF_SYM_TYPE(type)) {
1644 nm_opts.value_print_fn(sym);
1646 if (sym->st_size != 0)
1647 nm_opts.size_print_fn(sym);
1653 sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym,
1657 if (sec == NULL || sym == NULL || name == NULL ||
1658 nm_opts.value_print_fn == NULL)
1661 PRINT_DEMANGLED_NAME("%-20s|", name);
1662 if (IS_UNDEF_SYM_TYPE(type))
1665 nm_opts.value_print_fn(sym);
1667 printf("| %c |", type);
1669 switch (sym->st_info & 0xf) {
1671 printf("%18s|", "OBJECT");
1675 printf("%18s|", "FUNC");
1679 printf("%18s|", "SECTION");
1683 printf("%18s|", "FILE");
1687 printf("%18s|", "LOPROC");
1691 printf("%18s|", "HIPROC");
1696 printf("%18s|", "NOTYPE");
1699 if (sym->st_size != 0)
1700 nm_opts.size_print_fn(sym);
1704 printf("| |%s", sec);
1708 sym_elem_def(char type, const GElf_Sym *sym, const char *name)
1711 assert(IS_SYM_TYPE((unsigned char) type));
1716 return (!IS_UNDEF_SYM_TYPE((unsigned char) type));
1720 sym_elem_global(char type, const GElf_Sym *sym, const char *name)
1723 assert(IS_SYM_TYPE((unsigned char) type));
1728 /* weak symbols resemble global. */
1729 return (isupper((unsigned char) type) || type == 'w');
1733 sym_elem_global_static(char type, const GElf_Sym *sym, const char *name)
1737 assert(sym != NULL);
1742 info = sym->st_info >> 4;
1744 return (info == STB_LOCAL ||
1745 info == STB_GLOBAL ||
1750 sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name)
1753 assert(sym != NULL);
1758 if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE)
1760 if (sym->st_name == 0)
1767 sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name)
1770 assert(sym != NULL);
1775 return (sym->st_size > 0);
1779 sym_elem_undef(char type, const GElf_Sym *sym, const char *name)
1782 assert(IS_SYM_TYPE((unsigned char) type));
1787 return (IS_UNDEF_SYM_TYPE((unsigned char) type));
1791 sym_list_dest(struct sym_head *headp)
1793 struct sym_entry *ep, *ep_n;
1798 ep = STAILQ_FIRST(headp);
1799 while (ep != NULL) {
1800 ep_n = STAILQ_NEXT(ep, sym_entries);
1809 sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym)
1811 struct sym_entry *e;
1813 if (headp == NULL || name == NULL || sym == NULL)
1815 if ((e = malloc(sizeof(struct sym_entry))) == NULL) {
1819 if ((e->name = strdup(name)) == NULL) {
1824 if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) {
1831 memcpy(e->sym, sym, sizeof(GElf_Sym));
1833 /* Display size instead of value for common symbol. */
1834 if (sym->st_shndx == SHN_COMMON)
1835 e->sym->st_value = sym->st_size;
1837 STAILQ_INSERT_TAIL(headp, e, sym_entries);
1842 /* If file has not .debug_info, line_info will be NULL */
1844 sym_list_print(struct sym_print_data *p, struct func_info_head *func_info,
1845 struct var_info_head *var_info, struct line_info_head *line_info)
1847 struct sym_entry *e_v;
1851 if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1853 if ((e_v = sym_list_sort(p)) == NULL)
1855 if (nm_opts.sort_reverse == false)
1856 for (si = 0; si != p->list_num; ++si)
1857 sym_list_print_each(&e_v[si], p, func_info, var_info,
1860 for (i = p->list_num - 1; i != -1; --i)
1861 sym_list_print_each(&e_v[i], p, func_info, var_info,
1867 /* If file has not .debug_info, line_info will be NULL */
1869 sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p,
1870 struct func_info_head *func_info, struct var_info_head *var_info,
1871 struct line_info_head *line_info)
1876 if (ep == NULL || CHECK_SYM_PRINT_DATA(p))
1879 assert(ep->name != NULL);
1880 assert(ep->sym != NULL);
1882 type = get_sym_type(ep->sym, p->t_table);
1884 if (nm_opts.print_name == PRINT_NAME_FULL) {
1885 printf("%s", p->filename);
1886 if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) {
1887 if (p->objname != NULL)
1888 printf("[%s]", p->objname);
1891 if (p->objname != NULL)
1892 printf(":%s", p->objname);
1897 switch (ep->sym->st_shndx) {
1899 /* LOPROC or LORESERVE */
1918 /* HIRESERVE or XINDEX */
1919 sec = "*HIRESERVE*";
1922 if (ep->sym->st_shndx > p->sh_num)
1924 sec = p->s_table[ep->sym->st_shndx];
1928 nm_opts.elem_print_fn(type, sec, ep->sym, ep->name);
1930 if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type))
1931 print_lineno(ep, func_info, var_info, line_info);
1936 static struct sym_entry *
1937 sym_list_sort(struct sym_print_data *p)
1939 struct sym_entry *ep, *e_v;
1942 if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1945 if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) {
1951 STAILQ_FOREACH(ep, p->headp, sym_entries) {
1952 if (ep->name != NULL && ep->sym != NULL) {
1953 e_v[idx].name = ep->name;
1954 e_v[idx].sym = ep->sym;
1959 assert((size_t)idx == p->list_num);
1961 if (nm_opts.sort_fn != &cmp_none) {
1963 assert(nm_print_data != NULL);
1964 qsort(e_v, p->list_num, sizeof(struct sym_entry),
1972 sym_size_oct_print(const GElf_Sym *sym)
1975 assert(sym != NULL && "sym is null");
1976 printf("%016" PRIo64, sym->st_size);
1980 sym_size_hex_print(const GElf_Sym *sym)
1983 assert(sym != NULL && "sym is null");
1984 if (nm_elfclass == ELFCLASS32)
1985 printf("%08" PRIx64, sym->st_size);
1987 printf("%016" PRIx64, sym->st_size);
1991 sym_size_dec_print(const GElf_Sym *sym)
1994 assert(sym != NULL && "sym is null");
1995 printf("%016" PRId64, sym->st_size);
1999 sym_value_oct_print(const GElf_Sym *sym)
2002 assert(sym != NULL && "sym is null");
2003 printf("%016" PRIo64, sym->st_value);
2007 sym_value_hex_print(const GElf_Sym *sym)
2010 assert(sym != NULL && "sym is null");
2011 if (nm_elfclass == ELFCLASS32)
2012 printf("%08" PRIx64, sym->st_value);
2014 printf("%016" PRIx64, sym->st_value);
2018 sym_value_dec_print(const GElf_Sym *sym)
2021 assert(sym != NULL && "sym is null");
2022 printf("%016" PRId64, sym->st_value);
2029 printf("Usage: %s [options] file ...\
2030 \n Display symbolic information in file.\n\
2032 \n -A, --print-file-name Write the full pathname or library name of an\
2033 \n object on each line.\
2034 \n -a, --debug-syms Display all symbols include debugger-only\
2035 \n symbols.", nm_info.name);
2037 \n -B Equivalent to specifying \"--format=bsd\".\
2038 \n -C, --demangle[=style] Decode low-level symbol names.\
2039 \n --no-demangle Do not demangle low-level symbol names.\
2040 \n -D, --dynamic Display only dynamic symbols.\
2041 \n -e Display only global and static symbols.");
2043 \n -f Produce full output (default).\
2044 \n --format=format Display output in specific format. Allowed\
2045 \n formats are: \"bsd\", \"posix\" and \"sysv\".\
2046 \n -g, --extern-only Display only global symbol information.\
2047 \n -h, --help Show this help message.\
2048 \n -l, --line-numbers Display filename and linenumber using\
2049 \n debugging information.\
2050 \n -n, --numeric-sort Sort symbols numerically by value.");
2052 \n -o Write numeric values in octal. Equivalent to\
2053 \n specifying \"-t o\".\
2054 \n -p, --no-sort Do not sort symbols.\
2055 \n -P Write information in a portable output format.\
2056 \n Equivalent to specifying \"--format=posix\".\
2057 \n -r, --reverse-sort Reverse the order of the sort.\
2058 \n -S, --print-size Print symbol sizes instead values.\
2059 \n -s, --print-armap Include an index of archive members.\
2060 \n --size-sort Sort symbols by size.");
2062 \n -t, --radix=format Write each numeric value in the specified\
2066 \n x In hexadecimal.");
2068 \n -u, --undefined-only Display only undefined symbols.\
2069 \n --defined-only Display only defined symbols.\
2070 \n -V, --version Show the version identifier for %s.\
2071 \n -v Sort output by value.\
2072 \n -x Write numeric values in hexadecimal.\
2073 \n Equivalent to specifying \"-t x\".",
2076 \n The default options are: output in bsd format, use a hexadecimal radix,\
2077 \n sort by symbol name, do not demangle names.\n");
2083 * Display symbolic information in file.
2084 * Return 0 at success, >0 at failed.
2087 main(int argc, char **argv)
2092 get_opt(argc, argv);
2093 rtn = read_files(argc - optind, argv + optind);