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