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