xref: /freebsd/contrib/elftoolchain/nm/nm.c (revision f18976136625a7d016e97bfd9eabddf640b3e06d)
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 3504 2016-12-17 15:33:16Z kaiwang27 $");
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
775 global_dest(void)
776 {
777 
778 	filter_dest();
779 }
780 
781 static 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
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
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
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
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
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
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
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
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
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 *
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
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
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 	GElf_Half i;
1187 	Dwarf_Line *lbuf;
1188 	Dwarf_Unsigned lineno;
1189 	Dwarf_Signed lcount, filecount;
1190 	Dwarf_Addr lineaddr;
1191 	struct sym_print_data p_data;
1192 	struct sym_head list_head;
1193 	struct line_info_head *line_info;
1194 	struct func_info_head *func_info;
1195 	struct var_info_head *var_info;
1196 	struct line_info_entry *lie;
1197 	struct func_info_entry *func;
1198 	struct var_info_entry *var;
1199 	const char *shname, *objname;
1200 	char *type_table, **sec_table, *sfile, **src_files;
1201 	size_t shstrndx, shnum, dynndx, strndx;
1202 	int ret, rtn, e_err;
1203 
1204 #define	OBJNAME	(objname == NULL ? filename : objname)
1205 
1206 	assert(filename != NULL && "filename is null");
1207 
1208 	STAILQ_INIT(&list_head);
1209 	type_table = NULL;
1210 	sec_table = NULL;
1211 	line_info = NULL;
1212 	func_info = NULL;
1213 	var_info = NULL;
1214 	objname = NULL;
1215 	dynndx = SHN_UNDEF;
1216 	strndx = SHN_UNDEF;
1217 	rtn = 0;
1218 
1219 	nm_elfclass = gelf_getclass(elf);
1220 
1221 	if (kind == ELF_K_AR) {
1222 		if ((arhdr = elf_getarhdr(elf)) == NULL)
1223 			goto next_cmd;
1224 		objname = arhdr->ar_name != NULL ? arhdr->ar_name :
1225 		    arhdr->ar_rawname;
1226 	}
1227 	if (!elf_getshnum(elf, &shnum)) {
1228 		if ((e_err = elf_errno()) != 0)
1229 			warnx("%s: %s", OBJNAME, "File format not recognized");
1230 		else
1231 			warnx("%s: cannot get section number", OBJNAME);
1232 		rtn = 1;
1233 		goto next_cmd;
1234 	}
1235 	if (shnum == 0) {
1236 		warnx("%s: has no section", OBJNAME);
1237 		rtn = 1;
1238 		goto next_cmd;
1239 	}
1240 	if (!elf_getshstrndx(elf, &shstrndx)) {
1241 		warnx("%s: cannot get str index", OBJNAME);
1242 		rtn = 1;
1243 		goto next_cmd;
1244 	}
1245 	/* type_table for type determine */
1246 	if ((type_table = malloc(sizeof(char) * shnum)) == NULL) {
1247 		warn("%s: malloc", OBJNAME);
1248 		rtn = 1;
1249 		goto next_cmd;
1250 	}
1251 	/* sec_table for section name to display in sysv format */
1252 	if ((sec_table = calloc(shnum, sizeof(char *))) == NULL) {
1253 		warn("%s: calloc", OBJNAME);
1254 		rtn = 1;
1255 		goto next_cmd;
1256 	}
1257 
1258 	type_table[0] = 'U';
1259 	if ((sec_table[0] = strdup("*UND*")) == NULL) {
1260 		warn("strdup");
1261 		goto next_cmd;
1262 	}
1263 
1264 	for (i = 1; i < shnum; ++i) {
1265 		type_table[i] = 'U';
1266 		if ((scn = elf_getscn(elf, i)) == NULL) {
1267 			if ((e_err = elf_errno()) != 0)
1268 				warnx("%s: %s", OBJNAME, elf_errmsg(e_err));
1269 			else
1270 				warnx("%s: cannot get section", OBJNAME);
1271 			rtn = 1;
1272 			goto next_cmd;
1273 		}
1274 		if (gelf_getshdr(scn, &shdr) == NULL)
1275 			goto next_cmd;
1276 
1277 		/*
1278 		 * Cannot test by type and attribute for dynstr, strtab
1279 		 */
1280 		shname = elf_strptr(elf, shstrndx, (size_t) shdr.sh_name);
1281 		if (shname != NULL) {
1282 			if ((sec_table[i] = strdup(shname)) == NULL) {
1283 				warn("strdup");
1284 				goto next_cmd;
1285 			}
1286 			if (!strncmp(shname, ".dynstr", 7)) {
1287 				dynndx = elf_ndxscn(scn);
1288 				if (dynndx == SHN_UNDEF) {
1289 					warnx("%s: elf_ndxscn failed: %s",
1290 					    OBJNAME, elf_errmsg(-1));
1291 					goto next_cmd;
1292 				}
1293 			}
1294 			if (!strncmp(shname, ".strtab", 7)) {
1295 				strndx = elf_ndxscn(scn);
1296 				if (strndx == SHN_UNDEF) {
1297 					warnx("%s: elf_ndxscn failed: %s",
1298 					    OBJNAME, elf_errmsg(-1));
1299 					goto next_cmd;
1300 				}
1301 			}
1302 		} else {
1303 			sec_table[i] = strdup("*UND*");
1304 			if (sec_table[i] == NULL) {
1305 				warn("strdup");
1306 				goto next_cmd;
1307 			}
1308 		}
1309 
1310 
1311 		if (is_sec_text(&shdr))
1312 			type_table[i] = 'T';
1313 		else if (is_sec_data(&shdr)) {
1314 			if (is_sec_readonly(&shdr))
1315 				type_table[i] = 'R';
1316 			else
1317 				type_table[i] = 'D';
1318 		} else if (is_sec_nobits(&shdr))
1319 			type_table[i] = 'B';
1320 		else if (is_sec_debug(shname))
1321 			type_table[i] = 'N';
1322 		else if (is_sec_readonly(&shdr) && !is_sec_nobits(&shdr))
1323 			type_table[i] = 'n';
1324 	}
1325 
1326 	print_header(filename, objname);
1327 
1328 	if ((dynndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_DYN) ||
1329 	    (strndx == SHN_UNDEF && nm_opts.print_symbol == PRINT_SYM_SYM)) {
1330 		warnx("%s: no symbols", OBJNAME);
1331 		/* This is not an error case */
1332 		goto next_cmd;
1333 	}
1334 
1335 	STAILQ_INIT(&list_head);
1336 
1337 	if (!nm_opts.debug_line)
1338 		goto process_sym;
1339 
1340 	/*
1341 	 * Collect dwarf line number information.
1342 	 */
1343 
1344 	if (dwarf_elf_init(elf, DW_DLC_READ, NULL, NULL, &dbg, &de) !=
1345 	    DW_DLV_OK) {
1346 		warnx("dwarf_elf_init failed: %s", dwarf_errmsg(de));
1347 		goto process_sym;
1348 	}
1349 
1350 	line_info = malloc(sizeof(struct line_info_head));
1351 	func_info = malloc(sizeof(struct func_info_head));
1352 	var_info = malloc(sizeof(struct var_info_head));
1353 	if (line_info != NULL)
1354 		SLIST_INIT(line_info);
1355 	if (func_info != NULL)
1356 		SLIST_INIT(func_info);
1357 	if (var_info != NULL)
1358 		SLIST_INIT(var_info);
1359 	if (line_info == NULL || func_info == NULL || var_info == NULL) {
1360 		warn("malloc");
1361 		(void) dwarf_finish(dbg, &de);
1362 		goto process_sym;
1363 	}
1364 
1365 	while ((ret = dwarf_next_cu_header(dbg, NULL, NULL, NULL, NULL, NULL,
1366 	    &de)) ==  DW_DLV_OK) {
1367 		die = NULL;
1368 		while (dwarf_siblingof(dbg, die, &die, &de) == DW_DLV_OK) {
1369 			if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {
1370 				warnx("dwarf_tag failed: %s",
1371 				    dwarf_errmsg(de));
1372 				continue;
1373 			}
1374 			/* XXX: What about DW_TAG_partial_unit? */
1375 			if (tag == DW_TAG_compile_unit)
1376 				break;
1377 		}
1378 		if (die == NULL) {
1379 			warnx("could not find DW_TAG_compile_unit die");
1380 			continue;
1381 		}
1382 
1383 		/* Retrieve source file list. */
1384 		ret = dwarf_srcfiles(die, &src_files, &filecount, &de);
1385 		if (ret == DW_DLV_ERROR)
1386 			warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1387 		if (ret != DW_DLV_OK)
1388 			continue;
1389 
1390 		/*
1391 		 * Retrieve line number information from .debug_line section.
1392 		 */
1393 
1394 		ret = dwarf_srclines(die, &lbuf, &lcount, &de);
1395 		if (ret == DW_DLV_ERROR)
1396 			warnx("dwarf_srclines: %s", dwarf_errmsg(de));
1397 		if (ret != DW_DLV_OK)
1398 			goto line_attr;
1399 		for (i = 0; (Dwarf_Signed) i < lcount; i++) {
1400 			if (dwarf_lineaddr(lbuf[i], &lineaddr, &de)) {
1401 				warnx("dwarf_lineaddr: %s", dwarf_errmsg(de));
1402 				continue;
1403 			}
1404 			if (dwarf_lineno(lbuf[i], &lineno, &de)) {
1405 				warnx("dwarf_lineno: %s", dwarf_errmsg(de));
1406 				continue;
1407 			}
1408 			if (dwarf_linesrc(lbuf[i], &sfile, &de)) {
1409 				warnx("dwarf_linesrc: %s", dwarf_errmsg(de));
1410 				continue;
1411 			}
1412 			if ((lie = malloc(sizeof(*lie))) == NULL) {
1413 				warn("malloc");
1414 				continue;
1415 			}
1416 			lie->addr = lineaddr;
1417 			lie->line = lineno;
1418 			lie->file = strdup(sfile);
1419 			if (lie->file == NULL) {
1420 				warn("strdup");
1421 				free(lie);
1422 				continue;
1423 			}
1424 			SLIST_INSERT_HEAD(line_info, lie, entries);
1425 		}
1426 
1427 	line_attr:
1428 		/* Retrieve line number information from DIEs. */
1429 		search_line_attr(dbg, func_info, var_info, die, src_files, filecount);
1430 	}
1431 
1432 	(void) dwarf_finish(dbg, &de);
1433 
1434 process_sym:
1435 
1436 	p_data.list_num = get_sym(elf, &list_head, shnum, dynndx, strndx,
1437 	    type_table, (void *) sec_table, shnum);
1438 
1439 	if (p_data.list_num == 0)
1440 		goto next_cmd;
1441 
1442 	p_data.headp = &list_head;
1443 	p_data.sh_num = shnum;
1444 	p_data.t_table = type_table;
1445 	p_data.s_table = (void *) sec_table;
1446 	p_data.filename = filename;
1447 	p_data.objname = objname;
1448 
1449 	sym_list_print(&p_data, func_info, var_info, line_info);
1450 
1451 next_cmd:
1452 	if (nm_opts.debug_line) {
1453 		if (func_info != NULL) {
1454 			while (!SLIST_EMPTY(func_info)) {
1455 				func = SLIST_FIRST(func_info);
1456 				SLIST_REMOVE_HEAD(func_info, entries);
1457 				free(func->file);
1458 				free(func->name);
1459 				free(func);
1460 			}
1461 			free(func_info);
1462 			func_info = NULL;
1463 		}
1464 		if (var_info != NULL) {
1465 			while (!SLIST_EMPTY(var_info)) {
1466 				var = SLIST_FIRST(var_info);
1467 				SLIST_REMOVE_HEAD(var_info, entries);
1468 				free(var->file);
1469 				free(var->name);
1470 				free(var);
1471 			}
1472 			free(var_info);
1473 			var_info = NULL;
1474 		}
1475 		if (line_info != NULL) {
1476 			while (!SLIST_EMPTY(line_info)) {
1477 				lie = SLIST_FIRST(line_info);
1478 				SLIST_REMOVE_HEAD(line_info, entries);
1479 				free(lie->file);
1480 				free(lie);
1481 			}
1482 			free(line_info);
1483 			line_info = NULL;
1484 		}
1485 	}
1486 
1487 	if (sec_table != NULL)
1488 		for (i = 0; i < shnum; ++i)
1489 			free(sec_table[i]);
1490 	free(sec_table);
1491 	free(type_table);
1492 
1493 	sym_list_dest(&list_head);
1494 
1495 	return (rtn);
1496 
1497 #undef	OBJNAME
1498 }
1499 
1500 static int
1501 read_object(const char *filename)
1502 {
1503 	Elf *elf, *arf;
1504 	Elf_Cmd elf_cmd;
1505 	Elf_Kind kind;
1506 	int fd, rtn, e_err;
1507 
1508 	assert(filename != NULL && "filename is null");
1509 
1510 	if ((fd = fileargs_open(nm_opts.fileargs, filename)) == -1) {
1511 		warn("'%s'", filename);
1512 		return (1);
1513 	}
1514 
1515 	elf_cmd = ELF_C_READ;
1516 	if ((arf = elf_begin(fd, elf_cmd, (Elf *) NULL)) == NULL) {
1517 		if ((e_err = elf_errno()) != 0)
1518 			warnx("elf_begin error: %s", elf_errmsg(e_err));
1519 		else
1520 			warnx("elf_begin error");
1521 		close(fd);
1522 		return (1);
1523 	}
1524 
1525 	assert(arf != NULL && "arf is null.");
1526 
1527 	rtn = 0;
1528 	if ((kind = elf_kind(arf)) == ELF_K_NONE) {
1529 		warnx("%s: File format not recognized", filename);
1530 		elf_end(arf);
1531 		close(fd);
1532 		return (1);
1533 	}
1534 	if (kind == ELF_K_AR) {
1535 		if (nm_opts.print_name == PRINT_NAME_MULTI &&
1536 		    nm_opts.elem_print_fn == sym_elem_print_all)
1537 			printf("\n%s:\n", filename);
1538 		if (nm_opts.print_armap == true)
1539 			print_ar_index(fd, arf);
1540 	}
1541 
1542 	while ((elf = elf_begin(fd, elf_cmd, arf)) != NULL) {
1543 		rtn |= read_elf(elf, filename, kind);
1544 
1545 		/*
1546 		 * If file is not archive, elf_next return ELF_C_NULL and
1547 		 * stop the loop.
1548 		 */
1549 		elf_cmd = elf_next(elf);
1550 		elf_end(elf);
1551 	}
1552 
1553 	elf_end(arf);
1554 	close(fd);
1555 
1556 	return (rtn);
1557 }
1558 
1559 static int
1560 read_files(int argc, char **argv)
1561 {
1562 	int rtn = 0;
1563 
1564 	if (argc < 0 || argv == NULL)
1565 		return (1);
1566 
1567 	if (argc == 0)
1568 		rtn |= read_object(nm_info.def_filename);
1569 	else {
1570 		if (nm_opts.print_name == PRINT_NAME_NONE && argc > 1)
1571 			nm_opts.print_name = PRINT_NAME_MULTI;
1572 		while (argc > 0) {
1573 			rtn |= read_object(*argv);
1574 			--argc;
1575 			++argv;
1576 		}
1577 	}
1578 
1579 	return (rtn);
1580 }
1581 
1582 static void
1583 print_lineno(struct sym_entry *ep, struct func_info_head *func_info,
1584     struct var_info_head *var_info, struct line_info_head *line_info)
1585 {
1586 	struct func_info_entry *func;
1587 	struct var_info_entry *var;
1588 	struct line_info_entry *lie;
1589 
1590 	/* For function symbol, search the function line information list.  */
1591 	if ((ep->sym->st_info & 0xf) == STT_FUNC && func_info != NULL) {
1592 		SLIST_FOREACH(func, func_info, entries) {
1593 			if (func->name != NULL &&
1594 			    !strcmp(ep->name, func->name) &&
1595 			    ep->sym->st_value >= func->lowpc &&
1596 			    ep->sym->st_value < func->highpc) {
1597 				printf("\t%s:%" PRIu64, func->file, func->line);
1598 				return;
1599 			}
1600 		}
1601 	}
1602 
1603 	/* For variable symbol, search the variable line information list.  */
1604 	if ((ep->sym->st_info & 0xf) == STT_OBJECT && var_info != NULL) {
1605 		SLIST_FOREACH(var, var_info, entries) {
1606 			if (!strcmp(ep->name, var->name) &&
1607 			    ep->sym->st_value == var->addr) {
1608 				printf("\t%s:%" PRIu64, var->file, var->line);
1609 				return;
1610 			}
1611 		}
1612 	}
1613 
1614 	/* Otherwise search line number information the .debug_line section. */
1615 	if (line_info != NULL) {
1616 		SLIST_FOREACH(lie, line_info, entries) {
1617 			if (ep->sym->st_value == lie->addr) {
1618 				printf("\t%s:%" PRIu64, lie->file, lie->line);
1619 				return;
1620 			}
1621 		}
1622 	}
1623 }
1624 
1625 static void
1626 set_opt_value_print_fn(enum radix t)
1627 {
1628 
1629 	switch (t) {
1630 	case RADIX_OCT:
1631 		nm_opts.value_print_fn = &sym_value_oct_print;
1632 		nm_opts.size_print_fn = &sym_size_oct_print;
1633 
1634 		break;
1635 	case RADIX_DEC:
1636 		nm_opts.value_print_fn = &sym_value_dec_print;
1637 		nm_opts.size_print_fn = &sym_size_dec_print;
1638 
1639 		break;
1640 	case RADIX_HEX:
1641 	default :
1642 		nm_opts.value_print_fn = &sym_value_hex_print;
1643 		nm_opts.size_print_fn  = &sym_size_hex_print;
1644 	}
1645 
1646 	assert(nm_opts.value_print_fn != NULL &&
1647 	    "nm_opts.value_print_fn is null");
1648 }
1649 
1650 static void
1651 sym_elem_print_all(char type, const char *sec, const GElf_Sym *sym,
1652     const char *name)
1653 {
1654 
1655 	if (sec == NULL || sym == NULL || name == NULL ||
1656 	    nm_opts.value_print_fn == NULL)
1657 		return;
1658 
1659 	if (IS_UNDEF_SYM_TYPE(type)) {
1660 		if (nm_opts.t == RADIX_HEX && nm_elfclass == ELFCLASS32)
1661 			printf("%-8s", "");
1662 		else
1663 			printf("%-16s", "");
1664 	} else {
1665 		switch ((nm_opts.sort_fn == & cmp_size ? 2 : 0) +
1666 		    nm_opts.print_size) {
1667 		case 3:
1668 			if (sym->st_size != 0) {
1669 				nm_opts.value_print_fn(sym);
1670 				printf(" ");
1671 				nm_opts.size_print_fn(sym);
1672 			}
1673 			break;
1674 
1675 		case 2:
1676 			if (sym->st_size != 0)
1677 				nm_opts.size_print_fn(sym);
1678 			break;
1679 
1680 		case 1:
1681 			nm_opts.value_print_fn(sym);
1682 			if (sym->st_size != 0) {
1683 				printf(" ");
1684 				nm_opts.size_print_fn(sym);
1685 			}
1686 			break;
1687 
1688 		case 0:
1689 		default:
1690 			nm_opts.value_print_fn(sym);
1691 		}
1692 	}
1693 
1694 	printf(" %c ", type);
1695 	PRINT_DEMANGLED_NAME("%s", name);
1696 }
1697 
1698 static void
1699 sym_elem_print_all_portable(char type, const char *sec, const GElf_Sym *sym,
1700     const char *name)
1701 {
1702 
1703 	if (sec == NULL || sym == NULL || name == NULL ||
1704 	    nm_opts.value_print_fn == NULL)
1705 		return;
1706 
1707 	PRINT_DEMANGLED_NAME("%s", name);
1708 	printf(" %c ", type);
1709 	if (!IS_UNDEF_SYM_TYPE(type)) {
1710 		nm_opts.value_print_fn(sym);
1711 		printf(" ");
1712 		if (sym->st_size != 0)
1713 			nm_opts.size_print_fn(sym);
1714 	} else
1715 		printf("        ");
1716 }
1717 
1718 static void
1719 sym_elem_print_all_sysv(char type, const char *sec, const GElf_Sym *sym,
1720     const char *name)
1721 {
1722 
1723 	if (sec == NULL || sym == NULL || name == NULL ||
1724 	    nm_opts.value_print_fn == NULL)
1725 		return;
1726 
1727 	PRINT_DEMANGLED_NAME("%-20s|", name);
1728 	if (IS_UNDEF_SYM_TYPE(type))
1729 		printf("                ");
1730 	else
1731 		nm_opts.value_print_fn(sym);
1732 
1733 	printf("|   %c  |", type);
1734 
1735 	switch (sym->st_info & 0xf) {
1736 	case STT_OBJECT:
1737 		printf("%18s|", "OBJECT");
1738 		break;
1739 
1740 	case STT_FUNC:
1741 		printf("%18s|", "FUNC");
1742 		break;
1743 
1744 	case STT_SECTION:
1745 		printf("%18s|", "SECTION");
1746 		break;
1747 
1748 	case STT_FILE:
1749 		printf("%18s|", "FILE");
1750 		break;
1751 
1752 	case STT_LOPROC:
1753 		printf("%18s|", "LOPROC");
1754 		break;
1755 
1756 	case STT_HIPROC:
1757 		printf("%18s|", "HIPROC");
1758 		break;
1759 
1760 	case STT_NOTYPE:
1761 	default:
1762 		printf("%18s|", "NOTYPE");
1763 	}
1764 
1765 	if (sym->st_size != 0)
1766 		nm_opts.size_print_fn(sym);
1767 	else
1768 		printf("                ");
1769 
1770 	printf("|     |%s", sec);
1771 }
1772 
1773 static int
1774 sym_elem_def(char type, const GElf_Sym *sym, const char *name)
1775 {
1776 
1777 	assert(IS_SYM_TYPE((unsigned char) type));
1778 
1779 	UNUSED(sym);
1780 	UNUSED(name);
1781 
1782 	return (!IS_UNDEF_SYM_TYPE((unsigned char) type));
1783 }
1784 
1785 static int
1786 sym_elem_global(char type, const GElf_Sym *sym, const char *name)
1787 {
1788 
1789 	assert(IS_SYM_TYPE((unsigned char) type));
1790 
1791 	UNUSED(sym);
1792 	UNUSED(name);
1793 
1794 	/* weak symbols resemble global. */
1795 	return (isupper((unsigned char) type) || type == 'w');
1796 }
1797 
1798 static int
1799 sym_elem_global_static(char type, const GElf_Sym *sym, const char *name)
1800 {
1801 	unsigned char info;
1802 
1803 	assert(sym != NULL);
1804 
1805 	UNUSED(type);
1806 	UNUSED(name);
1807 
1808 	info = sym->st_info >> 4;
1809 
1810 	return (info == STB_LOCAL ||
1811 	    info == STB_GLOBAL ||
1812 	    info == STB_WEAK);
1813 }
1814 
1815 static int
1816 sym_elem_nondebug(char type, const GElf_Sym *sym, const char *name)
1817 {
1818 
1819 	assert(sym != NULL);
1820 
1821 	UNUSED(type);
1822 	UNUSED(name);
1823 
1824 	if (sym->st_value == 0 && (sym->st_info & 0xf) == STT_FILE)
1825 		return (0);
1826 	if (sym->st_name == 0)
1827 		return (0);
1828 
1829 	return (1);
1830 }
1831 
1832 static int
1833 sym_elem_nonzero_size(char type, const GElf_Sym *sym, const char *name)
1834 {
1835 
1836 	assert(sym != NULL);
1837 
1838 	UNUSED(type);
1839 	UNUSED(name);
1840 
1841 	return (sym->st_size > 0);
1842 }
1843 
1844 static int
1845 sym_elem_undef(char type, const GElf_Sym *sym, const char *name)
1846 {
1847 
1848 	assert(IS_SYM_TYPE((unsigned char) type));
1849 
1850 	UNUSED(sym);
1851 	UNUSED(name);
1852 
1853 	return (IS_UNDEF_SYM_TYPE((unsigned char) type));
1854 }
1855 
1856 static void
1857 sym_list_dest(struct sym_head *headp)
1858 {
1859 	struct sym_entry *ep, *ep_n;
1860 
1861 	if (headp == NULL)
1862 		return;
1863 
1864 	ep = STAILQ_FIRST(headp);
1865 	while (ep != NULL) {
1866 		ep_n = STAILQ_NEXT(ep, sym_entries);
1867 		free(ep->sym);
1868 		free(ep->name);
1869 		free(ep);
1870 		ep = ep_n;
1871 	}
1872 }
1873 
1874 static int
1875 sym_list_insert(struct sym_head *headp, const char *name, const GElf_Sym *sym)
1876 {
1877 	struct sym_entry *e;
1878 
1879 	if (headp == NULL || name == NULL || sym == NULL)
1880 		return (0);
1881 	if ((e = malloc(sizeof(struct sym_entry))) == NULL) {
1882 		warn("malloc");
1883 		return (0);
1884 	}
1885 	if ((e->name = strdup(name)) == NULL) {
1886 		warn("strdup");
1887 		free(e);
1888 		return (0);
1889 	}
1890 	if ((e->sym = malloc(sizeof(GElf_Sym))) == NULL) {
1891 		warn("malloc");
1892 		free(e->name);
1893 		free(e);
1894 		return (0);
1895 	}
1896 
1897 	memcpy(e->sym, sym, sizeof(GElf_Sym));
1898 
1899 	/* Display size instead of value for common symbol. */
1900 	if (sym->st_shndx == SHN_COMMON)
1901 		e->sym->st_value = sym->st_size;
1902 
1903 	STAILQ_INSERT_TAIL(headp, e, sym_entries);
1904 
1905 	return (1);
1906 }
1907 
1908 /* If file has not .debug_info, line_info will be NULL */
1909 static void
1910 sym_list_print(struct sym_print_data *p, struct func_info_head *func_info,
1911     struct var_info_head *var_info, struct line_info_head *line_info)
1912 {
1913 	struct sym_entry *e_v;
1914 	size_t si;
1915 	int i;
1916 
1917 	if (p == NULL || CHECK_SYM_PRINT_DATA(p))
1918 		return;
1919 	if ((e_v = sym_list_sort(p)) == NULL)
1920 		return;
1921 	if (nm_opts.sort_reverse == false)
1922 		for (si = 0; si != p->list_num; ++si)
1923 			sym_list_print_each(&e_v[si], p, func_info, var_info,
1924 			    line_info);
1925 	else
1926 		for (i = p->list_num - 1; i != -1; --i)
1927 			sym_list_print_each(&e_v[i], p, func_info, var_info,
1928 			    line_info);
1929 
1930 	free(e_v);
1931 }
1932 
1933 /* If file has not .debug_info, line_info will be NULL */
1934 static void
1935 sym_list_print_each(struct sym_entry *ep, struct sym_print_data *p,
1936     struct func_info_head *func_info, struct var_info_head *var_info,
1937     struct line_info_head *line_info)
1938 {
1939 	const char *sec;
1940 	char type;
1941 
1942 	if (ep == NULL || CHECK_SYM_PRINT_DATA(p))
1943 		return;
1944 
1945 	assert(ep->name != NULL);
1946 	assert(ep->sym != NULL);
1947 
1948 	type = get_sym_type(ep->sym, p->t_table);
1949 
1950 	if (nm_opts.print_name == PRINT_NAME_FULL) {
1951 		printf("%s", p->filename);
1952 		if (nm_opts.elem_print_fn == &sym_elem_print_all_portable) {
1953 			if (p->objname != NULL)
1954 				printf("[%s]", p->objname);
1955 			printf(": ");
1956 		} else {
1957 			if (p->objname != NULL)
1958 				printf(":%s", p->objname);
1959 			printf(":");
1960 		}
1961 	}
1962 
1963 	switch (ep->sym->st_shndx) {
1964 	case SHN_LOPROC:
1965 		/* LOPROC or LORESERVE */
1966 		sec = "*LOPROC*";
1967 		break;
1968 	case SHN_HIPROC:
1969 		sec = "*HIPROC*";
1970 		break;
1971 	case SHN_LOOS:
1972 		sec = "*LOOS*";
1973 		break;
1974 	case SHN_HIOS:
1975 		sec = "*HIOS*";
1976 		break;
1977 	case SHN_ABS:
1978 		sec = "*ABS*";
1979 		break;
1980 	case SHN_COMMON:
1981 		sec = "*COM*";
1982 		break;
1983 	case SHN_HIRESERVE:
1984 		/* HIRESERVE or XINDEX */
1985 		sec = "*HIRESERVE*";
1986 		break;
1987 	default:
1988 		if (ep->sym->st_shndx > p->sh_num)
1989 			return;
1990 		sec = p->s_table[ep->sym->st_shndx];
1991 		break;
1992 	}
1993 
1994 	nm_opts.elem_print_fn(type, sec, ep->sym, ep->name);
1995 
1996 	if (nm_opts.debug_line == true && !IS_UNDEF_SYM_TYPE(type))
1997 		print_lineno(ep, func_info, var_info, line_info);
1998 
1999 	printf("\n");
2000 }
2001 
2002 static struct sym_entry	*
2003 sym_list_sort(struct sym_print_data *p)
2004 {
2005 	struct sym_entry *ep, *e_v;
2006 	int idx;
2007 
2008 	if (p == NULL || CHECK_SYM_PRINT_DATA(p))
2009 		return (NULL);
2010 
2011 	if ((e_v = malloc(sizeof(struct sym_entry) * p->list_num)) == NULL) {
2012 		warn("malloc");
2013 		return (NULL);
2014 	}
2015 
2016 	idx = 0;
2017 	STAILQ_FOREACH(ep, p->headp, sym_entries) {
2018 		if (ep->name != NULL && ep->sym != NULL) {
2019 			e_v[idx].name = ep->name;
2020 			e_v[idx].sym = ep->sym;
2021 			++idx;
2022 		}
2023 	}
2024 
2025 	assert((size_t)idx == p->list_num);
2026 
2027 	if (nm_opts.sort_fn != &cmp_none) {
2028 		nm_print_data = p;
2029 		assert(nm_print_data != NULL);
2030 		qsort(e_v, p->list_num, sizeof(struct sym_entry),
2031 		    nm_opts.sort_fn);
2032 	}
2033 
2034 	return (e_v);
2035 }
2036 
2037 static void
2038 sym_size_oct_print(const GElf_Sym *sym)
2039 {
2040 
2041 	assert(sym != NULL && "sym is null");
2042 	printf("%016" PRIo64, sym->st_size);
2043 }
2044 
2045 static void
2046 sym_size_hex_print(const GElf_Sym *sym)
2047 {
2048 
2049 	assert(sym != NULL && "sym is null");
2050 	if (nm_elfclass == ELFCLASS32)
2051 		printf("%08" PRIx64, sym->st_size);
2052 	else
2053 		printf("%016" PRIx64, sym->st_size);
2054 }
2055 
2056 static void
2057 sym_size_dec_print(const GElf_Sym *sym)
2058 {
2059 
2060 	assert(sym != NULL && "sym is null");
2061 	printf("%016" PRId64, sym->st_size);
2062 }
2063 
2064 static void
2065 sym_value_oct_print(const GElf_Sym *sym)
2066 {
2067 
2068 	assert(sym != NULL && "sym is null");
2069 	printf("%016" PRIo64, sym->st_value);
2070 }
2071 
2072 static void
2073 sym_value_hex_print(const GElf_Sym *sym)
2074 {
2075 
2076 	assert(sym != NULL && "sym is null");
2077 	if (nm_elfclass == ELFCLASS32)
2078 		printf("%08" PRIx64, sym->st_value);
2079 	else
2080 		printf("%016" PRIx64, sym->st_value);
2081 }
2082 
2083 static void
2084 sym_value_dec_print(const GElf_Sym *sym)
2085 {
2086 
2087 	assert(sym != NULL && "sym is null");
2088 	printf("%016" PRId64, sym->st_value);
2089 }
2090 
2091 static void
2092 usage(int exitcode)
2093 {
2094 
2095 	printf("Usage: %s [options] file ...\
2096 \n  Display symbolic information in file.\n\
2097 \n  Options: \
2098 \n  -A, --print-file-name     Write the full pathname or library name of an\
2099 \n                            object on each line.\
2100 \n  -a, --debug-syms          Display all symbols include debugger-only\
2101 \n                            symbols.", nm_info.name);
2102 	printf("\
2103 \n  -B                        Equivalent to specifying \"--format=bsd\".\
2104 \n  -C, --demangle[=style]    Decode low-level symbol names.\
2105 \n      --no-demangle         Do not demangle low-level symbol names.\
2106 \n  -D, --dynamic             Display only dynamic symbols.\
2107 \n  -e                        Display only global and static symbols.");
2108 	printf("\
2109 \n  -f                        Produce full output (default).\
2110 \n      --format=format       Display output in specific format.  Allowed\
2111 \n                            formats are: \"bsd\", \"posix\" and \"sysv\".\
2112 \n  -g, --extern-only         Display only global symbol information.\
2113 \n  -h, --help                Show this help message.\
2114 \n  -l, --line-numbers        Display filename and linenumber using\
2115 \n                            debugging information.\
2116 \n  -n, --numeric-sort        Sort symbols numerically by value.");
2117 	printf("\
2118 \n  -o                        Write numeric values in octal. Equivalent to\
2119 \n                            specifying \"-t o\".\
2120 \n  -p, --no-sort             Do not sort symbols.\
2121 \n  -P                        Write information in a portable output format.\
2122 \n                            Equivalent to specifying \"--format=posix\".\
2123 \n  -r, --reverse-sort        Reverse the order of the sort.\
2124 \n  -S, --print-size          Print symbol sizes instead values.\
2125 \n  -s, --print-armap         Include an index of archive members.\
2126 \n      --size-sort           Sort symbols by size.");
2127 	printf("\
2128 \n  -t, --radix=format        Write each numeric value in the specified\
2129 \n                            format:\
2130 \n                               d   In decimal,\
2131 \n                               o   In octal,\
2132 \n                               x   In hexadecimal.");
2133 	printf("\
2134 \n  -u, --undefined-only      Display only undefined symbols.\
2135 \n      --defined-only        Display only defined symbols.\
2136 \n  -V, --version             Show the version identifier for %s.\
2137 \n  -v                        Sort output by value.\
2138 \n  -x                        Write numeric values in hexadecimal.\
2139 \n                            Equivalent to specifying \"-t x\".",
2140 	    nm_info.name);
2141 	printf("\n\
2142 \n  The default options are: output in bsd format, use a hexadecimal radix,\
2143 \n  sort by symbol name, do not demangle names.\n");
2144 
2145 	exit(exitcode);
2146 }
2147 
2148 /*
2149  * Display symbolic information in file.
2150  * Return 0 at success, >0 at failed.
2151  */
2152 int
2153 main(int argc, char **argv)
2154 {
2155 	int rtn;
2156 
2157 	global_init();
2158 	get_opt(&argc, &argv);
2159 	enter_cap_mode(argc, argv);
2160 	rtn = read_files(argc, argv);
2161 	global_dest();
2162 
2163 	exit(rtn);
2164 }
2165