xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/main.c (revision 7a088f03b431bdffa96c3b2175964d4d38420caa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Dump an elf file.
29  */
30 #include	<sys/param.h>
31 #include	<fcntl.h>
32 #include	<stdio.h>
33 #include	<stdlib.h>
34 #include	<ctype.h>
35 #include	<libelf.h>
36 #include	<link.h>
37 #include	<stdarg.h>
38 #include	<unistd.h>
39 #include	<libgen.h>
40 #include	<libintl.h>
41 #include	<locale.h>
42 #include	<errno.h>
43 #include	<strings.h>
44 #include	<debug.h>
45 #include	<conv.h>
46 #include	<msg.h>
47 #include	<_elfdump.h>
48 #include	<sys/elf_SPARC.h>
49 #include	<sys/elf_amd64.h>
50 
51 
52 const Cache	cache_init = {NULL, NULL, NULL, NULL, 0};
53 
54 
55 
56 /*
57  * The -I, -N, and -T options are called "match options", because
58  * they allow selecting the items to be displayed based on matching
59  * their index, name, or type.
60  *
61  * The ELF information to which -I, -N, or -T are applied in
62  * the current invocation is called the "match item".
63  */
64 typedef enum {
65 	MATCH_ITEM_PT,		/* Program header (PT_) */
66 	MATCH_ITEM_SHT		/* Section header (SHT_) */
67 } match_item_t;
68 
69 /* match_opt_t is  used to note which match option was used */
70 typedef enum {
71 	MATCH_OPT_NAME,		/* Record contains a name */
72 	MATCH_OPT_NDX,		/* Record contains a single index */
73 	MATCH_OPT_RANGE,	/* Record contains an index range */
74 	MATCH_OPT_TYPE,		/* Record contains a type (shdr or phdr) */
75 } match_opt_t;
76 
77 typedef struct _match {
78 	struct _match	*next;		/* Pointer to next item in list */
79 	match_opt_t	opt_type;
80 	union {
81 		const char	*name;	/* MATCH_OPT_NAME */
82 		struct {		/* MATCH_OPT_NDX and MATCH_OPT_RANGE */
83 			int	start;
84 			int	end;	/* Only for MATCH_OPT_RANGE */
85 		} ndx;
86 		uint32_t	type;	/* MATCH_OPT_TYPE */
87 	} value;
88 } match_rec_t;
89 
90 static struct {
91 	match_item_t	item_type;	/* Type of item being matched */
92 	match_rec_t	*list;		/* Records for (-I, -N, -T) options */
93 } match_state;
94 
95 
96 
97 /* Map names to their integer value */
98 typedef struct {
99 	const char	*sym_name;
100 	uint32_t	sym_value;
101 } atoui_sym_t;
102 
103 /*
104  * ELF section types.
105  */
106 static atoui_sym_t sym_sht[] = {
107 	{ MSG_ORIG(MSG_SHT_NULL),		SHT_NULL },
108 	{ MSG_ORIG(MSG_SHT_NULL_ALT1),		SHT_NULL },
109 
110 	{ MSG_ORIG(MSG_SHT_PROGBITS),		SHT_PROGBITS },
111 	{ MSG_ORIG(MSG_SHT_PROGBITS_ALT1),	SHT_PROGBITS },
112 
113 	{ MSG_ORIG(MSG_SHT_SYMTAB),		SHT_SYMTAB },
114 	{ MSG_ORIG(MSG_SHT_SYMTAB_ALT1),	SHT_SYMTAB },
115 
116 	{ MSG_ORIG(MSG_SHT_STRTAB),		SHT_STRTAB },
117 	{ MSG_ORIG(MSG_SHT_STRTAB_ALT1),	SHT_STRTAB },
118 
119 	{ MSG_ORIG(MSG_SHT_RELA),		SHT_RELA },
120 	{ MSG_ORIG(MSG_SHT_RELA_ALT1),		SHT_RELA },
121 
122 	{ MSG_ORIG(MSG_SHT_HASH),		SHT_HASH },
123 	{ MSG_ORIG(MSG_SHT_HASH_ALT1),		SHT_HASH },
124 
125 	{ MSG_ORIG(MSG_SHT_DYNAMIC),		SHT_DYNAMIC },
126 	{ MSG_ORIG(MSG_SHT_DYNAMIC_ALT1),	SHT_DYNAMIC },
127 
128 	{ MSG_ORIG(MSG_SHT_NOTE),		SHT_NOTE },
129 	{ MSG_ORIG(MSG_SHT_NOTE_ALT1),		SHT_NOTE },
130 
131 	{ MSG_ORIG(MSG_SHT_NOBITS),		SHT_NOBITS },
132 	{ MSG_ORIG(MSG_SHT_NOBITS_ALT1),	SHT_NOBITS },
133 
134 	{ MSG_ORIG(MSG_SHT_REL),		SHT_REL },
135 	{ MSG_ORIG(MSG_SHT_REL_ALT1),		SHT_REL },
136 
137 	{ MSG_ORIG(MSG_SHT_SHLIB),		SHT_SHLIB },
138 	{ MSG_ORIG(MSG_SHT_SHLIB_ALT1),		SHT_SHLIB },
139 
140 	{ MSG_ORIG(MSG_SHT_DYNSYM),		SHT_DYNSYM },
141 	{ MSG_ORIG(MSG_SHT_DYNSYM_ALT1),	SHT_DYNSYM },
142 
143 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY),		SHT_INIT_ARRAY },
144 	{ MSG_ORIG(MSG_SHT_INIT_ARRAY_ALT1),	SHT_INIT_ARRAY },
145 
146 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY),		SHT_FINI_ARRAY },
147 	{ MSG_ORIG(MSG_SHT_FINI_ARRAY_ALT1),	SHT_FINI_ARRAY },
148 
149 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY),	SHT_PREINIT_ARRAY },
150 	{ MSG_ORIG(MSG_SHT_PREINIT_ARRAY_ALT1),	SHT_PREINIT_ARRAY },
151 
152 	{ MSG_ORIG(MSG_SHT_GROUP),		SHT_GROUP },
153 	{ MSG_ORIG(MSG_SHT_GROUP_ALT1),		SHT_GROUP },
154 
155 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX),	SHT_SYMTAB_SHNDX },
156 	{ MSG_ORIG(MSG_SHT_SYMTAB_SHNDX_ALT1),	SHT_SYMTAB_SHNDX },
157 
158 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT),	SHT_SUNW_symsort },
159 	{ MSG_ORIG(MSG_SHT_SUNW_SYMSORT_ALT1),	SHT_SUNW_symsort },
160 
161 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT),	SHT_SUNW_tlssort },
162 	{ MSG_ORIG(MSG_SHT_SUNW_TLSSORT_ALT1),	SHT_SUNW_tlssort },
163 
164 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM),	SHT_SUNW_LDYNSYM },
165 	{ MSG_ORIG(MSG_SHT_SUNW_LDYNSYM_ALT1),	SHT_SUNW_LDYNSYM },
166 
167 	{ MSG_ORIG(MSG_SHT_SUNW_DOF),		SHT_SUNW_dof },
168 	{ MSG_ORIG(MSG_SHT_SUNW_DOF_ALT1),	SHT_SUNW_dof },
169 
170 	{ MSG_ORIG(MSG_SHT_SUNW_CAP),		SHT_SUNW_cap },
171 	{ MSG_ORIG(MSG_SHT_SUNW_CAP_ALT1),	SHT_SUNW_cap },
172 
173 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE),	SHT_SUNW_SIGNATURE },
174 	{ MSG_ORIG(MSG_SHT_SUNW_SIGNATURE_ALT1), SHT_SUNW_SIGNATURE },
175 
176 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE),	SHT_SUNW_ANNOTATE },
177 	{ MSG_ORIG(MSG_SHT_SUNW_ANNOTATE_ALT1),	SHT_SUNW_ANNOTATE },
178 
179 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR),	SHT_SUNW_DEBUGSTR },
180 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUGSTR_ALT1),	SHT_SUNW_DEBUGSTR },
181 
182 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG),		SHT_SUNW_DEBUG },
183 	{ MSG_ORIG(MSG_SHT_SUNW_DEBUG_ALT1),	SHT_SUNW_DEBUG },
184 
185 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE),		SHT_SUNW_move },
186 	{ MSG_ORIG(MSG_SHT_SUNW_MOVE_ALT1),	SHT_SUNW_move },
187 
188 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT),	SHT_SUNW_COMDAT },
189 	{ MSG_ORIG(MSG_SHT_SUNW_COMDAT_ALT1),	SHT_SUNW_COMDAT },
190 
191 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO),	SHT_SUNW_syminfo },
192 	{ MSG_ORIG(MSG_SHT_SUNW_SYMINFO_ALT1),	SHT_SUNW_syminfo },
193 
194 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF),	SHT_SUNW_verdef },
195 	{ MSG_ORIG(MSG_SHT_SUNW_VERDEF_ALT1),	SHT_SUNW_verdef },
196 
197 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF),		SHT_GNU_verdef },
198 	{ MSG_ORIG(MSG_SHT_GNU_VERDEF_ALT1),	SHT_GNU_verdef },
199 
200 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED),	SHT_SUNW_verneed },
201 	{ MSG_ORIG(MSG_SHT_SUNW_VERNEED_ALT1),	SHT_SUNW_verneed },
202 
203 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED),	SHT_GNU_verneed },
204 	{ MSG_ORIG(MSG_SHT_GNU_VERNEED_ALT1),	SHT_GNU_verneed },
205 
206 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM),	SHT_SUNW_versym },
207 	{ MSG_ORIG(MSG_SHT_SUNW_VERSYM_ALT1),	SHT_SUNW_versym },
208 
209 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM),		SHT_GNU_versym },
210 	{ MSG_ORIG(MSG_SHT_GNU_VERSYM_ALT1),	SHT_GNU_versym },
211 
212 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA),	SHT_SPARC_GOTDATA },
213 	{ MSG_ORIG(MSG_SHT_SPARC_GOTDATA_ALT1),	SHT_SPARC_GOTDATA },
214 
215 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND),	SHT_AMD64_UNWIND },
216 	{ MSG_ORIG(MSG_SHT_AMD64_UNWIND_ALT1),	SHT_AMD64_UNWIND },
217 
218 	{ NULL }
219 };
220 
221 /*
222  * Program header PT_* type values
223  */
224 static atoui_sym_t sym_pt[] = {
225 	{ MSG_ORIG(MSG_PT_NULL),		PT_NULL },
226 	{ MSG_ORIG(MSG_PT_NULL_ALT1),		PT_NULL },
227 
228 	{ MSG_ORIG(MSG_PT_LOAD),		PT_LOAD },
229 	{ MSG_ORIG(MSG_PT_LOAD_ALT1),		PT_LOAD },
230 
231 	{ MSG_ORIG(MSG_PT_DYNAMIC),		PT_DYNAMIC },
232 	{ MSG_ORIG(MSG_PT_DYNAMIC_ALT1),	PT_DYNAMIC },
233 
234 	{ MSG_ORIG(MSG_PT_INTERP),		PT_INTERP },
235 	{ MSG_ORIG(MSG_PT_INTERP_ALT1),		PT_INTERP },
236 
237 	{ MSG_ORIG(MSG_PT_NOTE),		PT_NOTE },
238 	{ MSG_ORIG(MSG_PT_NOTE_ALT1),		PT_NOTE },
239 
240 	{ MSG_ORIG(MSG_PT_SHLIB),		PT_SHLIB },
241 	{ MSG_ORIG(MSG_PT_SHLIB_ALT1),		PT_SHLIB },
242 
243 	{ MSG_ORIG(MSG_PT_PHDR),		PT_PHDR },
244 	{ MSG_ORIG(MSG_PT_PHDR_ALT1),		PT_PHDR },
245 
246 	{ MSG_ORIG(MSG_PT_TLS),			PT_TLS },
247 	{ MSG_ORIG(MSG_PT_TLS_ALT1),		PT_TLS },
248 
249 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND),		PT_SUNW_UNWIND },
250 	{ MSG_ORIG(MSG_PT_SUNW_UNWIND_ALT1),	PT_SUNW_UNWIND },
251 
252 	{ MSG_ORIG(MSG_PT_SUNW_EH_FRAME),	PT_SUNW_EH_FRAME },
253 	{ MSG_ORIG(MSG_PT_SUNW_EH_FRAME_ALT1),	PT_SUNW_EH_FRAME },
254 
255 	{ MSG_ORIG(MSG_PT_SUNWBSS),		PT_SUNWBSS },
256 	{ MSG_ORIG(MSG_PT_SUNWBSS_ALT1),	PT_SUNWBSS },
257 
258 	{ MSG_ORIG(MSG_PT_SUNWSTACK),		PT_SUNWSTACK },
259 	{ MSG_ORIG(MSG_PT_SUNWSTACK_ALT1),	PT_SUNWSTACK },
260 
261 	{ MSG_ORIG(MSG_PT_SUNWDTRACE),		PT_SUNWDTRACE },
262 	{ MSG_ORIG(MSG_PT_SUNWDTRACE_ALT1),	PT_SUNWDTRACE },
263 
264 	{ MSG_ORIG(MSG_PT_SUNWCAP),		PT_SUNWCAP },
265 	{ MSG_ORIG(MSG_PT_SUNWCAP_ALT1),	PT_SUNWCAP },
266 
267 	{ NULL }
268 };
269 
270 
271 
272 
273 
274 const char *
275 _elfdump_msg(Msg mid)
276 {
277 	return (gettext(MSG_ORIG(mid)));
278 }
279 
280 /*
281  * Determine whether a symbol name should be demangled.
282  */
283 const char *
284 demangle(const char *name, uint_t flags)
285 {
286 	if (flags & FLG_CTL_DEMANGLE)
287 		return (Elf_demangle_name(name));
288 	else
289 		return ((char *)name);
290 }
291 
292 /*
293  * Define our own standard error routine.
294  */
295 void
296 failure(const char *file, const char *func)
297 {
298 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
299 	    file, func, elf_errmsg(elf_errno()));
300 }
301 
302 /*
303  * The full usage message
304  */
305 static void
306 detail_usage()
307 {
308 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
309 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
310 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
311 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
312 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
313 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
314 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
315 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
316 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
317 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
318 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
319 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
320 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
321 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
322 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
323 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
324 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
325 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
326 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
327 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
328 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL21));
329 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL22));
330 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL23));
331 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL24));
332 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL25));
333 }
334 
335 /*
336  * Output a block of raw data as hex bytes. Each row is given
337  * the index of the first byte in the row.
338  *
339  * entry:
340  *	data - Pointer to first byte of data to be displayed
341  *	n - # of bytes of data
342  *	prefix - String to be output before each line. Useful
343  *		for indenting output.
344  *	bytes_per_col - # of space separated bytes to output
345  *		in each column.
346  *	col_per_row - # of columns to output per row
347  *
348  * exit:
349  *	The formatted data has been sent to stdout. Each row of output
350  *	shows (bytes_per_col * col_per_row) bytes of data.
351  */
352 void
353 dump_hex_bytes(const void *data, size_t n, int indent,
354 	int bytes_per_col, int col_per_row)
355 {
356 	const uchar_t *ldata = data;
357 	int	bytes_per_row = bytes_per_col * col_per_row;
358 	int	ndx, byte, word;
359 	char	string[128], *str = string;
360 	char	index[MAXNDXSIZE];
361 	int	index_width;
362 	int	sp_prefix = 0;
363 
364 
365 	/*
366 	 * Determine the width to use for the index string. We follow
367 	 * 8-byte tab rules, but don't use an actual \t character so
368 	 * that the output can be arbitrarily shifted without odd
369 	 * tab effects, and so that all the columns line up no matter
370 	 * how many lines of output are produced.
371 	 */
372 	ndx = n / bytes_per_row;
373 	(void) snprintf(index, sizeof (index),
374 	    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
375 	index_width = strlen(index);
376 	index_width = S_ROUND(index_width, 8);
377 
378 	for (ndx = byte = word = 0; n > 0; n--, ldata++) {
379 		while (sp_prefix-- > 0)
380 			*str++ = ' ';
381 
382 		(void) snprintf(str, sizeof (string),
383 		    MSG_ORIG(MSG_HEXDUMP_TOK), (int)*ldata);
384 		str += 2;
385 		sp_prefix = 1;
386 
387 		if (++byte == bytes_per_col) {
388 			sp_prefix += 2;
389 			word++;
390 			byte = 0;
391 		}
392 		if (word == col_per_row) {
393 			*str = '\0';
394 			(void) snprintf(index, sizeof (index),
395 			    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
396 			dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW),
397 			    indent, MSG_ORIG(MSG_STR_EMPTY),
398 			    index_width, index, string);
399 			sp_prefix = 0;
400 			word = 0;
401 			ndx += bytes_per_row;
402 			str = string;
403 		}
404 	}
405 	if (byte || word) {
406 		*str = '\0';	/*  */
407 		(void) snprintf(index, sizeof (index),
408 		    MSG_ORIG(MSG_FMT_INDEX2), EC_WORD(ndx));
409 		dbg_print(0, MSG_ORIG(MSG_HEXDUMP_ROW), indent,
410 		    MSG_ORIG(MSG_STR_EMPTY), index_width, index, string);
411 	}
412 }
413 
414 /*
415  * Convert the ASCII representation of an index, or index range, into
416  * binary form, and store it in rec:
417  *
418  *	index: An positive or 0 valued integer
419  *	range: Two indexes, separated by a ':' character, denoting
420  *		a range of allowed values. If the second value is omitted,
421  *		any values equal to or greater than the first will match.
422  *
423  * exit:
424  *	On success, *rec is filled in with a MATCH_OPT_NDX or MATCH_OPT_RANGE
425  *	value, and this function returns (1). On failure, the contents
426  *	of *rec are undefined, and (0) is returned.
427  */
428 int
429 process_index_opt(const char *str, match_rec_t *rec)
430 {
431 #define	SKIP_BLANK for (; *str && isspace(*str); str++)
432 
433 	char	*endptr;
434 
435 	rec->value.ndx.start = strtol(str, &endptr, 10);
436 	/* Value must use some of the input, and be 0 or positive */
437 	if ((str == endptr) || (rec->value.ndx.start < 0))
438 		return (0);
439 	str = endptr;
440 
441 	SKIP_BLANK;
442 	if (*str != ':') {
443 		rec->opt_type = MATCH_OPT_NDX;
444 	} else {
445 		str++;					/* Skip the ':' */
446 		rec->opt_type = MATCH_OPT_RANGE;
447 		SKIP_BLANK;
448 		if (*str == '\0') {
449 			rec->value.ndx.end = -1;	/* Indicates "to end" */
450 		} else {
451 			rec->value.ndx.end = strtol(str, &endptr, 10);
452 			if ((str == endptr) || (rec->value.ndx.end < 0))
453 				return (0);
454 			str = endptr;
455 			SKIP_BLANK;
456 		}
457 	}
458 
459 	/* Syntax error if anything is left over */
460 	if (*str != '\0')
461 		return (0);
462 
463 	return (1);
464 
465 #undef	SKIP_BLANK
466 }
467 
468 /*
469  * Process the symbolic name to value mappings passed to the
470  * atoui() function.
471  *
472  * entry:
473  *	sym - NULL terminated array of name->value mappings.
474  *	value - Address of variable to receive corresponding value.
475  *
476  * exit:
477  *	If a mapping is found, *value is set to it, and True is returned.
478  *	Otherwise False is returned.
479  */
480 static int
481 atoui_sym_process(const char *str, const atoui_sym_t *sym, uint32_t *value)
482 {
483 	size_t		cmp_len;
484 	const char	*tail;
485 
486 	while (isspace(*str))
487 		str++;
488 
489 	tail = str + strlen(str);
490 	while ((tail > str) && isspace(*(tail - 1)))
491 		tail--;
492 
493 	cmp_len = tail - str;
494 
495 	for (; sym->sym_name != NULL; sym++) {
496 		if ((strlen(sym->sym_name) == cmp_len) &&
497 		    (strncasecmp(sym->sym_name, str, cmp_len) == 0)) {
498 			*value = sym->sym_value;
499 			return (1);
500 		}
501 	}
502 
503 	/* No symbolic mapping was found */
504 	return (0);
505 }
506 
507 
508 /*
509  * Convert a string to a numeric value. Strings starting with '0'
510  * are taken to be octal, those staring with '0x' are hex, and all
511  * others are decimal.
512  *
513  * entry:
514  *	str - String to be converted
515  *	sym - NULL, or NULL terminated array of name/value pairs.
516  *	v - Address of variable to receive resulting value.
517  *
518  * exit:
519  *	On success, returns True (1) and *v is set to the value.
520  *	On failure, returns False (0) and *v is undefined.
521  */
522 static int
523 atoui(const char *str, const atoui_sym_t *sym, uint32_t *v)
524 {
525 	char		*endptr;
526 
527 	if (sym && atoui_sym_process(str, sym, v))
528 		return (1);
529 
530 	*v = strtoull(str, &endptr, 0);
531 
532 	/* If the left over part contains anything but whitespace, fail */
533 	for (; *endptr; endptr++)
534 		if (!isspace(*endptr))
535 			return (0);
536 	return (1);
537 }
538 
539 /*
540  * Called after getopt() processing is finished if there is a non-empty
541  * match list. Prepares the matching code for use.
542  *
543  * exit:
544  *	Returns True (1) if no errors are encountered. Writes an
545  *	error string to stderr and returns False (0) otherwise.
546  */
547 static int
548 match_prepare(char *argv0, uint_t flags)
549 {
550 	atoui_sym_t	*sym;
551 	match_rec_t	*list;
552 	const char	*str;
553 	int		minus_p = (flags & FLG_SHOW_PHDR) != 0;
554 
555 	/*
556 	 * Flag ambiguous attempt to use match option with both -p and
557 	 * and one or more section SHOW options. In this case, we
558 	 * can't tell what type of item we're supposed to match against.
559 	 */
560 	if (minus_p && (flags & FLG_MASK_SHOW_SHDR)) {
561 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_AMBIG_MATCH),
562 		    basename(argv0));
563 		return (0);
564 	}
565 
566 	/* Set the match type, based on the presence of the -p option */
567 	if (minus_p) {
568 		match_state.item_type = MATCH_ITEM_PT;
569 		sym = sym_pt;
570 	} else {
571 		match_state.item_type = MATCH_ITEM_SHT;
572 		sym = sym_sht;
573 	}
574 
575 	/*
576 	 * Scan match list and perform any necessary fixups:
577 	 *
578 	 * MATCH_OPT_NAME: If -p is specified, convert MATCH_OPT_NAME (-N)
579 	 *	requests into MATCH_OPT_TYPE (-T).
580 	 *
581 	 * MATCH_OPT_TYPE: Now that we know item type we are matching
582 	 *	against, we can convert the string saved in the name
583 	 *	field during getopt() processing into an integer and
584 	 *	write it into the type field.
585 	 */
586 	for (list = match_state.list; list; list = list->next) {
587 		if ((list->opt_type == MATCH_OPT_NAME) && minus_p)
588 			list->opt_type = MATCH_OPT_TYPE;
589 
590 		if (list->opt_type != MATCH_OPT_TYPE)
591 			continue;
592 
593 		str = list->value.name;
594 		if (atoui(str, sym, &list->value.type) == 0) {
595 			const char *fmt = minus_p ?
596 			    MSG_INTL(MSG_ERR_BAD_T_PT) :
597 			    MSG_INTL(MSG_ERR_BAD_T_SHT);
598 
599 			(void) fprintf(stderr, fmt, basename(argv0), str);
600 			return (0);
601 		}
602 	}
603 
604 	return (1);
605 }
606 
607 
608 /*
609  * Returns True (1) if the item with the given name or index should
610  * be displayed, and False (0) if it should not be.
611  *
612  * entry:
613  *	match_flags - Bitmask specifying matching options, as described
614  *		in _elfdump.h.
615  *	name - If MATCH_F_NAME flag is set, name of item under
616  *		consideration. Otherwise ignored.
617  *		should not be considered.
618  *	ndx - If MATCH_F_NDX flag is set, index of item under consideration.
619  *	type - If MATCH_F_TYPE is set, type of item under consideration.
620  *		If MATCH_F_PHDR is set, this would be a program
621  *		header type (PT_). Otherwise, a section header type (SHT_).
622  *
623  * exit:
624  *	True will be returned if the given name/index matches those given
625  *	by one of the (-I, -N -T) command line options, or if no such option
626  *	was used in the command invocation and MATCH_F_STRICT is not
627  *	set.
628  */
629 int
630 match(match_flags_t match_flags, const char *name, uint_t ndx, uint_t type)
631 {
632 	match_item_t item_type = (match_flags & MATCH_F_PHDR) ?
633 	    MATCH_ITEM_PT  : MATCH_ITEM_SHT;
634 	match_rec_t *list;
635 
636 	/*
637 	 * If there is no match list, then we use the MATCH_F_STRICT
638 	 * flag to decide what to return. In the strict case, we return
639 	 * False (0), in the normal case, True (1).
640 	 */
641 	if (match_state.list == NULL)
642 		return ((match_flags & MATCH_F_STRICT) == 0);
643 
644 	/*
645 	 * If item being checked is not the current match type,
646 	 * then allow it.
647 	 */
648 	if (item_type != match_state.item_type)
649 		return (1);
650 
651 	/* Run through the match records and check for a hit */
652 	for (list = match_state.list; list; list = list->next) {
653 		switch (list->opt_type) {
654 		case MATCH_OPT_NAME:
655 			if (((match_flags & MATCH_F_NAME) == 0) ||
656 			    (name == NULL))
657 				break;
658 			if (strcmp(list->value.name, name) == 0)
659 				return (1);
660 			break;
661 		case MATCH_OPT_NDX:
662 			if ((match_flags & MATCH_F_NDX) &&
663 			    (ndx == list->value.ndx.start))
664 				return (1);
665 			break;
666 		case MATCH_OPT_RANGE:
667 			/*
668 			 * A range end value less than 0 means that any value
669 			 * above the start is acceptible.
670 			 */
671 			if ((match_flags & MATCH_F_NDX) &&
672 			    (ndx >= list->value.ndx.start) &&
673 			    ((list->value.ndx.end < 0) ||
674 			    (ndx <= list->value.ndx.end)))
675 				return (1);
676 			break;
677 
678 		case MATCH_OPT_TYPE:
679 			if ((match_flags & MATCH_F_TYPE) &&
680 			    (type == list->value.type))
681 				return (1);
682 			break;
683 		}
684 	}
685 
686 	/* Nothing matched */
687 	return (0);
688 }
689 
690 /*
691  * Add an entry to match_state.list for use by match(). This routine is for
692  * use during getopt() processing. It should not be called once
693  * match_prepare() has been called.
694  *
695  * Return True (1) for success. On failure, an error is written
696  * to stderr, and False (0) is returned.
697  */
698 static int
699 add_match_record(char *argv0, match_rec_t *data)
700 {
701 	match_rec_t	*rec;
702 	match_rec_t	*list;
703 
704 	if ((rec = malloc(sizeof (*rec))) == NULL) {
705 		int err = errno;
706 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
707 		    basename(argv0), strerror(err));
708 		return (0);
709 	}
710 
711 	*rec = *data;
712 
713 	/* Insert at end of match_state.list */
714 	if (match_state.list == NULL) {
715 		match_state.list = rec;
716 	} else {
717 		for (list = match_state.list; list->next != NULL;
718 		    list = list->next)
719 			;
720 		list->next = rec;
721 	}
722 
723 	rec->next = NULL;
724 	return (1);
725 }
726 
727 static int
728 decide(const char *file, int fd, Elf *elf, uint_t flags,
729     const char *wname, int wfd)
730 {
731 	int r;
732 
733 	if (gelf_getclass(elf) == ELFCLASS64)
734 		r = regular64(file, fd, elf, flags, wname, wfd);
735 	else
736 		r = regular32(file, fd, elf, flags, wname, wfd);
737 
738 	return (r);
739 }
740 
741 static int
742 archive(const char *file, int fd, Elf *elf, uint_t flags,
743     const char *wname, int wfd)
744 {
745 	Elf_Cmd		cmd = ELF_C_READ;
746 	Elf_Arhdr	*arhdr;
747 	Elf		*_elf = NULL;
748 	size_t		ptr;
749 	Elf_Arsym	*arsym = NULL;
750 
751 	/*
752 	 * Determine if the archive symbol table itself is required.
753 	 */
754 	if ((flags & FLG_SHOW_SYMBOLS) &&
755 	    match(MATCH_F_NAME, MSG_ORIG(MSG_ELF_ARSYM), 0, 0)) {
756 		/*
757 		 * Get the archive symbol table.
758 		 */
759 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
760 			/*
761 			 * The arsym could be 0 even though there was no error.
762 			 * Print the error message only when there was
763 			 * real error from elf_getarsym().
764 			 */
765 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
766 			return (0);
767 		}
768 	}
769 
770 	/*
771 	 * Print the archive symbol table only when the archive symbol
772 	 * table exists and it was requested to print.
773 	 */
774 	if (arsym) {
775 		size_t		cnt;
776 		char		index[MAXNDXSIZE];
777 		size_t		offset = 0, _offset = 0;
778 
779 		/*
780 		 * Print out all the symbol entries.
781 		 */
782 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_SYMTAB));
783 		dbg_print(0, MSG_INTL(MSG_ARCHIVE_FIELDS));
784 
785 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
786 			/*
787 			 * For each object obtain an elf descriptor so that we
788 			 * can establish the members name.  Note, we have had
789 			 * archives where the archive header has not been
790 			 * obtainable so be lenient with errors.
791 			 */
792 			if ((offset == 0) || ((arsym->as_off != 0) &&
793 			    (arsym->as_off != _offset))) {
794 
795 				if (_elf)
796 					(void) elf_end(_elf);
797 
798 				if (elf_rand(elf, arsym->as_off) !=
799 				    arsym->as_off) {
800 					failure(file, MSG_ORIG(MSG_ELF_RAND));
801 					arhdr = NULL;
802 				} else if ((_elf = elf_begin(fd,
803 				    ELF_C_READ, elf)) == 0) {
804 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
805 					arhdr = NULL;
806 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
807 					failure(file,
808 					    MSG_ORIG(MSG_ELF_GETARHDR));
809 					arhdr = NULL;
810 				}
811 
812 				_offset = arsym->as_off;
813 				if (offset == 0)
814 					offset = _offset;
815 			}
816 
817 			(void) snprintf(index, MAXNDXSIZE,
818 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
819 			if (arsym->as_off)
820 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM1), index,
821 				    /* LINTED */
822 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
823 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
824 				    demangle(arsym->as_name, flags) :
825 				    MSG_INTL(MSG_STR_NULL)));
826 			else
827 				dbg_print(0, MSG_ORIG(MSG_FMT_ARSYM2), index,
828 				    /* LINTED */
829 				    (int)arsym->as_off);
830 		}
831 
832 		if (_elf)
833 			(void) elf_end(_elf);
834 
835 		/*
836 		 * If we only need the archive symbol table return.
837 		 */
838 		if ((flags & FLG_SHOW_SYMBOLS) &&
839 		    match(MATCH_F_STRICT | MATCH_F_NAME,
840 		    MSG_ORIG(MSG_ELF_ARSYM), -1, -1))
841 			return (0);
842 
843 		/*
844 		 * Reset elf descriptor in preparation for processing each
845 		 * member.
846 		 */
847 		if (offset)
848 			(void) elf_rand(elf, offset);
849 	}
850 
851 	/*
852 	 * Process each object within the archive.
853 	 */
854 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
855 		char	name[MAXPATHLEN];
856 
857 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
858 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
859 			return (0);
860 		}
861 		if (*arhdr->ar_name != '/') {
862 			(void) snprintf(name, MAXPATHLEN,
863 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
864 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTR), name);
865 
866 			switch (elf_kind(_elf)) {
867 			case ELF_K_AR:
868 				if (archive(name, fd, _elf, flags,
869 				    wname, wfd) == 1)
870 					return (1);
871 				break;
872 			case ELF_K_ELF:
873 				if (decide(name, fd, _elf, flags,
874 				    wname, wfd) == 1)
875 					return (1);
876 				break;
877 			default:
878 				(void) fprintf(stderr,
879 				    MSG_INTL(MSG_ERR_BADFILE), name);
880 				break;
881 			}
882 		}
883 
884 		cmd = elf_next(_elf);
885 		(void) elf_end(_elf);
886 	}
887 
888 	return (0);
889 }
890 
891 int
892 main(int argc, char **argv, char **envp)
893 {
894 	Elf		*elf;
895 	int		var, fd, wfd = 0;
896 	char		*wname = NULL;
897 	uint_t		flags = 0;
898 	match_rec_t	match_data;
899 	int		ret;
900 
901 	/*
902 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
903 	 * the binary.  If successful, conv_check_native() won't return.
904 	 */
905 	(void) conv_check_native(argv, envp);
906 
907 	/*
908 	 * Establish locale.
909 	 */
910 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
911 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
912 
913 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
914 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
915 
916 	opterr = 0;
917 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
918 		switch (var) {
919 		case 'C':
920 			flags |= FLG_CTL_DEMANGLE;
921 			break;
922 		case 'c':
923 			flags |= FLG_SHOW_SHDR;
924 			break;
925 		case 'd':
926 			flags |= FLG_SHOW_DYNAMIC;
927 			break;
928 		case 'e':
929 			flags |= FLG_SHOW_EHDR;
930 			break;
931 		case 'G':
932 			flags |= FLG_SHOW_GOT;
933 			break;
934 		case 'g':
935 			flags |= FLG_SHOW_GROUP;
936 			break;
937 		case 'H':
938 			flags |= FLG_SHOW_CAP;
939 			break;
940 		case 'h':
941 			flags |= FLG_SHOW_HASH;
942 			break;
943 		case 'I':
944 			if (!process_index_opt(optarg, &match_data))
945 				goto usage_brief;
946 			if (!add_match_record(argv[0], &match_data))
947 				return (1);
948 			flags |= FLG_CTL_MATCH;
949 			break;
950 		case 'i':
951 			flags |= FLG_SHOW_INTERP;
952 			break;
953 		case 'k':
954 			flags |= FLG_CALC_CHECKSUM;
955 			break;
956 		case 'l':
957 			flags |= FLG_CTL_LONGNAME;
958 			break;
959 		case 'm':
960 			flags |= FLG_SHOW_MOVE;
961 			break;
962 		case 'N':
963 			match_data.opt_type = MATCH_OPT_NAME;
964 			match_data.value.name = optarg;
965 			if (!add_match_record(argv[0], &match_data))
966 				return (1);
967 			flags |= FLG_CTL_MATCH;
968 			break;
969 		case 'n':
970 			flags |= FLG_SHOW_NOTE;
971 			break;
972 		case 'P':
973 			flags |= FLG_CTL_FAKESHDR;
974 			break;
975 		case 'p':
976 			flags |= FLG_SHOW_PHDR;
977 			break;
978 		case 'r':
979 			flags |= FLG_SHOW_RELOC;
980 			break;
981 		case 'S':
982 			flags |= FLG_SHOW_SORT;
983 			break;
984 		case 's':
985 			flags |= FLG_SHOW_SYMBOLS;
986 			break;
987 		case 'T':
988 			/*
989 			 * We can't evaluate the value yet, because
990 			 * we need to know if -p is used or not in
991 			 * order to tell if we're seeing section header
992 			 * or program header types. So, we save the
993 			 * string in the name field, and then convert
994 			 * it to a type integer in a following pass.
995 			 */
996 			match_data.opt_type = MATCH_OPT_TYPE;
997 			match_data.value.name = optarg;
998 			if (!add_match_record(argv[0], &match_data))
999 				return (1);
1000 			flags |= FLG_CTL_MATCH;
1001 			break;
1002 		case 'u':
1003 			flags |= FLG_SHOW_UNWIND;
1004 			break;
1005 		case 'v':
1006 			flags |= FLG_SHOW_VERSIONS;
1007 			break;
1008 		case 'w':
1009 			wname = optarg;
1010 			break;
1011 		case 'y':
1012 			flags |= FLG_SHOW_SYMINFO;
1013 			break;
1014 		case '?':
1015 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
1016 			    basename(argv[0]));
1017 			detail_usage();
1018 			return (1);
1019 		default:
1020 			break;
1021 		}
1022 	}
1023 
1024 	/* -p and -w are mutually exclusive. -w only works with sections */
1025 	if (((flags & FLG_SHOW_PHDR) != 0) && (wname != NULL))
1026 		goto usage_brief;
1027 
1028 	/* If a match argument is present, prepare the match state */
1029 	if ((match_state.list != NULL) && (match_prepare(argv[0], flags) == 0))
1030 		return (1);
1031 
1032 	/*
1033 	 * Decide what to do if no options specifying something to
1034 	 * show or do are present.
1035 	 *
1036 	 * If there is no -w and no match options, then we will set all
1037 	 * the show flags, causing a full display of everything in the
1038 	 * file that we know how to handle.
1039 	 *
1040 	 * Otherwise, if there is no match list, we generate a usage
1041 	 * error and quit.
1042 	 *
1043 	 * In the case where there is a match list, we go ahead and call
1044 	 * regular() anyway, leaving it to decide what to do. If -w is
1045 	 * present, regular() will use the match list to handle it.
1046 	 * In addition, in the absence of explicit show/calc flags, regular()
1047 	 * will compare the section headers to the match list and use
1048 	 * that to generate the FLG_ bits that will display the information
1049 	 * specified by the match list.
1050 	 */
1051 	if ((flags & ~FLG_MASK_CTL) == 0) {
1052 		if (!wname && (match_state.list == NULL))
1053 			flags |= FLG_MASK_SHOW;
1054 		else if (match_state.list == NULL)
1055 			goto usage_brief;
1056 	}
1057 
1058 	/* There needs to be at least 1 filename left following the options */
1059 	if ((var = argc - optind) == 0)
1060 		goto usage_brief;
1061 
1062 	/*
1063 	 * If the -l/-C option is specified, set up the liblddbg.so.
1064 	 */
1065 	if (flags & FLG_CTL_LONGNAME)
1066 		dbg_desc->d_extra |= DBG_E_LONG;
1067 	if (flags & FLG_CTL_DEMANGLE)
1068 		dbg_desc->d_extra |= DBG_E_DEMANGLE;
1069 
1070 	/*
1071 	 * If the -w option has indicated an output file open it.  It's
1072 	 * arguable whether this option has much use when multiple files are
1073 	 * being processed.
1074 	 *
1075 	 * If wname is non-NULL, we know that -p was not specified, due
1076 	 * to the test above.
1077 	 */
1078 	if (wname) {
1079 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
1080 		    0666)) < 0) {
1081 			int err = errno;
1082 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
1083 			    wname, strerror(err));
1084 			return (1);
1085 		}
1086 	}
1087 
1088 	/*
1089 	 * Open the input file, initialize the elf interface, and
1090 	 * process it.
1091 	 */
1092 	ret = 0;
1093 	for (; (optind < argc) && (ret == 0); optind++) {
1094 		const char	*file = argv[optind];
1095 
1096 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
1097 			int err = errno;
1098 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
1099 			    file, strerror(err));
1100 			continue;
1101 		}
1102 		(void) elf_version(EV_CURRENT);
1103 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
1104 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
1105 			(void) close(fd);
1106 			continue;
1107 		}
1108 
1109 		if (var > 1)
1110 			dbg_print(0, MSG_ORIG(MSG_FMT_NLSTRNL), file);
1111 
1112 		switch (elf_kind(elf)) {
1113 		case ELF_K_AR:
1114 			ret = archive(file, fd, elf, flags, wname, wfd);
1115 			break;
1116 		case ELF_K_ELF:
1117 			ret = decide(file, fd, elf, flags, wname, wfd);
1118 			break;
1119 		default:
1120 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
1121 			break;
1122 		}
1123 
1124 		(void) close(fd);
1125 		(void) elf_end(elf);
1126 	}
1127 
1128 	if (wfd)
1129 		(void) close(wfd);
1130 	return (ret);
1131 
1132 usage_brief:
1133 	/* Control comes here for a simple usage message and exit */
1134 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
1135 	    basename(argv[0]));
1136 	return (1);
1137 
1138 }
1139