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