xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/elfdump.c (revision a07094369b21309434206d9b3601d162693466fc)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 
23 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  * Dump an elf file.
31  */
32 #include	<sys/param.h>
33 #include	<fcntl.h>
34 #include	<stdio.h>
35 #include	<libelf.h>
36 #include	<gelf.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	<sys/elf_SPARC.h>
46 #include	<sys/elf_386.h>
47 #include	<sys/elf_amd64.h>
48 #include	<debug.h>
49 #include	<_debug.h>
50 #include	<conv.h>
51 #include	<msg.h>
52 #include	<dwarf.h>
53 
54 #define	FLG_DYNAMIC	0x00000001
55 #define	FLG_EHDR	0x00000002
56 #define	FLG_INTERP	0x00000004
57 #define	FLG_SHDR	0x00000008
58 #define	FLG_NOTE	0x00000010
59 #define	FLG_PHDR	0x00000020
60 #define	FLG_RELOC	0x00000040
61 #define	FLG_SYMBOLS	0x00000080
62 #define	FLG_VERSIONS	0x00000100
63 #define	FLG_HASH	0x00000200
64 #define	FLG_GOT		0x00000400
65 #define	FLG_SYMINFO	0x00000800
66 #define	FLG_MOVE	0x00001000
67 #define	FLG_GROUP	0x00002000
68 #define	FLG_CAP		0x00004000
69 #define	FLG_UNWIND	0x00008000
70 #define	FLG_LONGNAME	0x00100000	/* not done by default */
71 #define	FLG_CHECKSUM	0x00200000	/* not done by default */
72 #define	FLG_DEMANGLE	0x00400000	/* not done by default */
73 
74 #define	FLG_EVERYTHING	0x000fffff
75 
76 #define	IAM_SPARC(X)	\
77 	((X == EM_SPARC) || (X == EM_SPARC32PLUS) || (X == EM_SPARCV9))
78 #define	IAM_INTEL(X)	\
79 	(X == EM_386)
80 
81 #define	MAXNDXSIZE	10
82 
83 typedef struct cache {
84 	GElf_Shdr	c_shdr;
85 	Elf_Data	*c_data;
86 	char		*c_name;
87 } Cache;
88 
89 typedef struct got_info {
90 	GElf_Word	g_rshtype;	/* it will never happen, but */
91 					/* support mixed relocations */
92 	GElf_Rela	g_rela;
93 	const char	*g_symname;
94 } Got_info;
95 
96 static const Cache	_cache_init = {{0}, NULL, NULL};
97 
98 const char *
99 _elfdump_msg(Msg mid)
100 {
101 	return (gettext(MSG_ORIG(mid)));
102 }
103 
104 /*
105  * Determine whether a symbol name should be demangled.
106  */
107 static const char *
108 demangle(const char *name, uint32_t flags)
109 {
110 	if (flags & FLG_DEMANGLE)
111 		return (Gelf_sym_dem(name));
112 	else
113 		return ((char *)name);
114 }
115 
116 
117 /*
118  * Define our own printing routine.  All Elf routines referenced call upon
119  * this routine to carry out the actual printing.
120  */
121 /*PRINTFLIKE1*/
122 void
123 dbg_print(const char *format, ...)
124 {
125 	va_list		ap;
126 
127 	va_start(ap, format);
128 	(void) vprintf(format, ap);
129 	(void) printf(MSG_ORIG(MSG_STR_NL));
130 	va_end(ap);
131 }
132 
133 /*
134  * Just like dbg_print - except that it does not insert
135  * a newline at the end.  Can be used for printing tables
136  * and such.
137  */
138 /*PRINTFLIKE1*/
139 void
140 dbg_printf(const char *format, ...)
141 {
142 	va_list	    ap;
143 	va_start(ap, format);
144 	(void) vprintf(format, ap);
145 	va_end(ap);
146 }
147 
148 
149 
150 /*
151  * Define our own standard error routine.
152  */
153 static void
154 failure(const char *file, const char *func)
155 {
156 	(void) fprintf(stderr, MSG_INTL(MSG_ERR_FAILURE),
157 	    file, func, elf_errmsg(elf_errno()));
158 	(void) fflush(stderr);
159 }
160 
161 
162 /*
163  * Focal point for verifying symbol names.
164  */
165 static const char *
166 string(Cache *refsec, GElf_Word ndx, Cache *strsec, const char *file,
167     ulong_t name)
168 {
169 	static Cache	*osec = 0;
170 	static int	nostr;
171 
172 	const char	*strs = (char *)strsec->c_data->d_buf;
173 	ulong_t		strn = strsec->c_data->d_size;
174 
175 	/*
176 	 * Only print a diagnoistic regarding an empty string table once per
177 	 * input section being processed.
178 	 */
179 	if (osec != refsec) {
180 		osec = refsec;
181 		nostr = 0;
182 	}
183 
184 	/*
185 	 * Is the string table offset within range of the available strings?
186 	 */
187 	if (name >= strn) {
188 		/*
189 		 * Do we have a empty string table?
190 		 */
191 		if (strs == 0) {
192 			if (nostr == 0) {
193 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
194 				    file, strsec->c_name);
195 				(void) fflush(stderr);
196 				nostr++;
197 			}
198 		} else {
199 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF),
200 			    file, refsec->c_name, ndx, strsec->c_name,
201 			    EC_XWORD(name), EC_XWORD(strn - 1));
202 			(void) fflush(stderr);
203 		}
204 
205 		/*
206 		 * Return the empty string so that the calling function can
207 		 * continue it's output diagnostics.
208 		 */
209 		return (MSG_INTL(MSG_STR_UNKNOWN));
210 	}
211 	return (strs + name);
212 }
213 
214 /*
215  * Lookup a symbol and set Sym accordingly.
216  *
217  * Returns:
218  *	1 - symbol found
219  *	0 - symbol not found
220  */
221 static int
222 symlookup(const char *name, Cache *cache, GElf_Word shnum, GElf_Sym *sym,
223     Cache *symtab, const char *file)
224 {
225 	GElf_Shdr *	shdr;
226 	GElf_Word	symn, cnt;
227 
228 	if (symtab == 0)
229 		return (0);
230 
231 	shdr = &symtab->c_shdr;
232 	/*
233 	 * Determine the symbol data and number.
234 	 */
235 	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
236 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
237 		    file, symtab->c_name);
238 		(void) fflush(stderr);
239 		return (0);
240 	}
241 	/* LINTED */
242 	symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize);
243 
244 	/*
245 	 * Get the associated string table section.
246 	 */
247 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
248 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
249 		    file, symtab->c_name, EC_XWORD(shdr->sh_link));
250 		(void) fflush(stderr);
251 		return (0);
252 	}
253 
254 	/*
255 	 * Loop through the symbol table to find a match.
256 	 */
257 	for (cnt = 0; cnt < symn; cnt++) {
258 		GElf_Sym	tsym;
259 		const char	*sname;
260 
261 		if (gelf_getsym(symtab->c_data, cnt, &tsym) == NULL) {
262 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM),
263 			    file, symtab->c_name, elf_errmsg(0));
264 			(void) fflush(stderr);
265 			return (0);
266 		}
267 
268 		sname = string(symtab, cnt, &cache[shdr->sh_link], file,
269 		    tsym.st_name);
270 
271 		if (strcmp(name, sname) == 0) {
272 			*sym = tsym;
273 			return (1);
274 		}
275 	}
276 	return (0);
277 }
278 
279 /*
280  * The full usage message
281  */
282 static void
283 detail_usage()
284 {
285 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL1));
286 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL2));
287 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL3));
288 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL4));
289 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL5));
290 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL6));
291 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL7));
292 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL8));
293 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9));
294 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL9_1));
295 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL10));
296 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL11));
297 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL12));
298 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL13));
299 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL14));
300 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL15));
301 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL16));
302 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL17));
303 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL18));
304 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL19));
305 	(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL20));
306 	(void) fflush(stderr);
307 }
308 
309 /*
310  * Print section headers.
311  */
312 static void
313 sections(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
314     GElf_Ehdr *ehdr, const char *name)
315 {
316 	GElf_Word	cnt;
317 	Cache *		_cache;
318 
319 	for (cnt = 1; cnt < shnum; cnt++) {
320 		GElf_Shdr	*shdr;
321 		const char	*sname;
322 
323 		_cache = &cache[cnt];
324 		sname = _cache->c_name;
325 		if (name && strcmp(name, sname))
326 			continue;
327 
328 		/*
329 		 * Although numerous section header entries can be zero, it's
330 		 * usually a sign of trouble if the name or type are zero.
331 		 */
332 		shdr = &_cache->c_shdr;
333 		if (shdr->sh_type == 0) {
334 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE),
335 			    file, sname, EC_XWORD(shdr->sh_type));
336 			(void) fflush(stderr);
337 		}
338 		if (shdr->sh_name == 0) {
339 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHNAME),
340 			    file, sname, EC_XWORD(shdr->sh_name));
341 			(void) fflush(stderr);
342 
343 			/*
344 			 * Use the empty string, rather than the fabricated
345 			 * name for the section output.
346 			 */
347 			sname = MSG_ORIG(MSG_STR_EMPTY);
348 		}
349 
350 		/*
351 		 * Identify any sections that are suspicious.  A .got section
352 		 * shouldn't exist in a relocatable object.
353 		 */
354 		if (ehdr->e_type == ET_REL) {
355 			if (strncmp(sname, MSG_ORIG(MSG_ELF_GOT),
356 			    MSG_ELF_GOT_SIZE) == 0) {
357 				(void) fprintf(stderr,
358 				    MSG_INTL(MSG_GOT_UNEXPECTED), file, sname);
359 				(void) fflush(stderr);
360 			}
361 		}
362 
363 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
364 		/* LINTED */
365 		dbg_print(MSG_INTL(MSG_ELF_SHDR), (uint_t)cnt, sname);
366 		Gelf_shdr_entry(ehdr->e_machine, shdr);
367 	}
368 }
369 
370 static void
371 unwind(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
372     const char *name, const char *file, Elf *elf)
373 {
374 	GElf_Word	cnt;
375 	GElf_Phdr	unwind_phdr;
376 	/*
377 	 * For the moment - UNWIND is only relevant for
378 	 * a AMD64 object
379 	 */
380 	if (ehdr->e_machine != EM_AMD64)
381 	    return;
382 
383 	unwind_phdr.p_type = PT_NULL;
384 
385 	for (cnt = 0; cnt < phnum; cnt++) {
386 		GElf_Phdr	phdr;
387 
388 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
389 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
390 			return;
391 		}
392 
393 		if (phdr.p_type == PT_SUNW_UNWIND) {
394 			unwind_phdr = phdr;
395 			break;
396 		}
397 	}
398 
399 
400 	for (cnt = 1; cnt < shnum; cnt++) {
401 		Cache		*_cache;
402 		GElf_Shdr	*shdr;
403 		unsigned char	*data;
404 		size_t		datasize;
405 		uint64_t	off, ndx;
406 
407 
408 		_cache = &cache[cnt];
409 		shdr = &_cache->c_shdr;
410 		/*
411 		 * XX64 - this is a strmcp() just to find the gcc
412 		 *	  produced sections.  Soon gcc should be
413 		 *	  settng the section type - and we'll not need
414 		 *	  this strcmp().
415 		 */
416 		if ((shdr->sh_type != SHT_AMD64_UNWIND) &&
417 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM),
418 		    MSG_SCN_FRM_SIZE) != 0) &&
419 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
420 		    MSG_SCN_FRMHDR_SIZE) != 0))
421 			continue;
422 		if (name && strcmp(name, _cache->c_name))
423 			continue;
424 
425 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
426 		dbg_print(MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name);
427 
428 		data = (unsigned char *)(_cache->c_data->d_buf);
429 		datasize = _cache->c_data->d_size;
430 		off = 0;
431 
432 		/*
433 		 * Is this a .eh_frame_hdr
434 		 */
435 		if (((unwind_phdr.p_type == PT_SUNW_UNWIND) &&
436 		    (shdr->sh_addr == unwind_phdr.p_vaddr)) ||
437 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
438 			MSG_SCN_FRMHDR_SIZE) == 0)) {
439 			    uint_t	vers;
440 			    uint_t	frame_ptr_enc;
441 			    uint64_t	frame_ptr;
442 			    uint_t	fde_cnt_enc;
443 			    uint64_t	fde_cnt;
444 			    uint_t	table_enc;
445 			    uint64_t	tabndx;
446 
447 			    dbg_print(MSG_ORIG(MSG_UNW_FRMHDR));
448 			    ndx = 0;
449 
450 			    vers = data[ndx++];
451 			    frame_ptr_enc = data[ndx++];
452 			    fde_cnt_enc = data[ndx++];
453 			    table_enc = data[ndx++];
454 
455 			    dbg_print(MSG_ORIG(MSG_UNW_FRMVERS), vers);
456 
457 			    frame_ptr = dwarf_ehe_extract(data,
458 				&ndx, frame_ptr_enc, ehdr->e_ident,
459 				shdr->sh_addr + ndx);
460 
461 			    dbg_print(MSG_ORIG(MSG_UNW_FRPTRENC),
462 				conv_dwarf_ehe_str(frame_ptr_enc),
463 				frame_ptr);
464 
465 			    fde_cnt = dwarf_ehe_extract(data,
466 				&ndx, fde_cnt_enc, ehdr->e_ident,
467 				shdr->sh_addr + ndx);
468 			    dbg_print(MSG_ORIG(MSG_UNW_FDCNENC),
469 				    conv_dwarf_ehe_str(fde_cnt_enc),
470 				    fde_cnt);
471 			    dbg_print(MSG_ORIG(MSG_UNW_TABENC),
472 				    conv_dwarf_ehe_str(table_enc));
473 			    dbg_print(MSG_ORIG(MSG_UNW_BINSRTAB1));
474 			    dbg_print(MSG_ORIG(MSG_UNW_BINSRTAB2));
475 
476 			    for (tabndx = 0; tabndx < fde_cnt; tabndx++) {
477 				    uint64_t	init_loc;
478 				    uint64_t	fde_loc;
479 				    init_loc = dwarf_ehe_extract(data,
480 					&ndx, table_enc, ehdr->e_ident,
481 					shdr->sh_addr);
482 				    fde_loc = dwarf_ehe_extract(data,
483 					&ndx, table_enc, ehdr->e_ident,
484 					shdr->sh_addr);
485 				    dbg_print(MSG_ORIG(MSG_UNW_BINSRTABENT),
486 					init_loc, fde_loc);
487 			    }
488 			    continue;
489 		}
490 
491 		/*
492 		 * Walk the Eh_frame's
493 		 */
494 		while (off < datasize) {
495 			uint_t		cieid, cielength, cieversion,
496 					cieretaddr;
497 			int		cieRflag, cieLflag,
498 					ciePflag, cieZflag;
499 			uint_t		length,	id;
500 			uint64_t	ciecalign, ciedalign;
501 			char		*cieaugstr;
502 			uint_t		cieaugndx;
503 
504 			ndx = 0;
505 			/*
506 			 * extract length in lsb format
507 			 */
508 			length = LSB32EXTRACT(data + off + ndx);
509 			ndx += 4;
510 
511 			/*
512 			 * extract CIE id in lsb format
513 			 */
514 			id = LSB32EXTRACT(data + off + ndx);
515 			ndx += 4;
516 
517 			/*
518 			 * A CIE record has a id of '0', otherwise
519 			 * this is a FDE entry and the 'id' is the
520 			 * CIE pointer.
521 			 */
522 			if (id == 0) {
523 				uint64_t    persVal;
524 				cielength = length;
525 				cieid = id;
526 
527 				cieLflag = 0;
528 				ciePflag = 0;
529 				cieRflag = 0;
530 				cieZflag = 0;
531 
532 				dbg_print(MSG_ORIG(MSG_UNW_CIE),
533 				    shdr->sh_addr + off);
534 				dbg_print(MSG_ORIG(MSG_UNW_CIELNGTH),
535 				    cielength, cieid);
536 				cieversion = data[off + ndx];
537 				ndx += 1;
538 				cieaugstr = (char *)(&data[off + ndx]);
539 				ndx += strlen(cieaugstr) + 1;
540 				dbg_print(MSG_ORIG(MSG_UNW_CIEVERS),
541 					cieversion, cieaugstr);
542 				ciecalign = uleb_extract(&data[off], &ndx);
543 				ciedalign = sleb_extract(&data[off], &ndx);
544 				cieretaddr = data[off + ndx];
545 				ndx += 1;
546 				dbg_print(MSG_ORIG(MSG_UNW_CIECALGN),
547 				    ciecalign, ciedalign, cieretaddr);
548 
549 				if (cieaugstr[0])
550 				    dbg_print(MSG_ORIG(MSG_UNW_CIEAUXVAL));
551 				for (cieaugndx = 0; cieaugstr[cieaugndx];
552 				    cieaugndx++) {
553 					uint_t	val;
554 					switch (cieaugstr[cieaugndx]) {
555 					case 'z':
556 					    val = uleb_extract(&data[off],
557 						&ndx);
558 					    dbg_print(
559 						MSG_ORIG(MSG_UNW_CIEAUXSIZE),
560 						val);
561 					    cieZflag = 1;
562 					    break;
563 					case 'P':
564 					    ciePflag = data[off + ndx];
565 					    ndx += 1;
566 
567 					    persVal = dwarf_ehe_extract(
568 						&data[off],
569 						&ndx, ciePflag, ehdr->e_ident,
570 						shdr->sh_addr + off + ndx);
571 					    dbg_print(
572 						MSG_ORIG(MSG_UNW_CIEAUXPERS),
573 						ciePflag,
574 						conv_dwarf_ehe_str(ciePflag),
575 						EC_XWORD(persVal));
576 					    break;
577 					case 'R':
578 					    val = data[off + ndx];
579 					    ndx += 1;
580 					    dbg_print(
581 						MSG_ORIG(MSG_UNW_CIEAUXCENC),
582 						val, conv_dwarf_ehe_str(val));
583 					    cieRflag = val;
584 					    break;
585 					case 'L':
586 					    val = data[off + ndx];
587 					    ndx += 1;
588 					    dbg_print(
589 						MSG_ORIG(MSG_UNW_CIEAUXLSDA),
590 						val, conv_dwarf_ehe_str(val));
591 					    cieLflag = val;
592 					    break;
593 					default:
594 					    dbg_print(
595 						MSG_ORIG(MSG_UNW_CIEAUXUNEC),
596 						cieaugstr[cieaugndx]);
597 					    break;
598 					}
599 				}
600 				if ((cielength + 4) > ndx) {
601 					uint_t	    cnt;
602 					dbg_printf(MSG_ORIG(MSG_UNW_CIECFI));
603 					cnt = 0;
604 					while (ndx < (cielength + 4)) {
605 						if ((cnt++ % 8) == 0) {
606 						    dbg_printf(
607 						    MSG_ORIG(MSG_UNW_CIECFI1));
608 						}
609 						dbg_printf(
610 						    MSG_ORIG(MSG_UNW_CIECFI2),
611 						    data[off + ndx++]);
612 					}
613 					dbg_print(MSG_ORIG(MSG_STR_EMPTY));
614 				}
615 				off += cielength + 4;
616 			} else {
617 				uint_t	    fdelength = length;
618 				int	    fdecieptr = id;
619 				uint64_t    fdeinitloc, fdeaddrrange;
620 
621 				dbg_print(MSG_ORIG(MSG_UNW_FDE),
622 				    shdr->sh_addr + off);
623 				dbg_print(MSG_ORIG(MSG_UNW_FDELNGTH),
624 				    fdelength, fdecieptr);
625 				fdeinitloc = dwarf_ehe_extract(&data[off],
626 				    &ndx, cieRflag, ehdr->e_ident,
627 				    shdr->sh_addr + off + ndx);
628 				fdeaddrrange = dwarf_ehe_extract(&data[off],
629 				    &ndx, (cieRflag & ~DW_EH_PE_pcrel),
630 				    ehdr->e_ident,
631 				    shdr->sh_addr + off + ndx);
632 				dbg_print(MSG_ORIG(MSG_UNW_FDEINITLOC),
633 				    fdeinitloc, fdeaddrrange);
634 				if (cieaugstr[0])
635 					dbg_print(MSG_ORIG(MSG_UNW_FDEAUXVAL));
636 				if (cieZflag) {
637 					uint64_t    val;
638 					val = uleb_extract(&data[off], &ndx);
639 					dbg_print(
640 					    MSG_ORIG(MSG_UNW_FDEAUXSIZE), val);
641 					if (val & cieLflag) {
642 					    fdeinitloc = dwarf_ehe_extract(
643 						&data[off], &ndx, cieLflag,
644 						ehdr->e_ident,
645 						shdr->sh_addr + off + ndx);
646 					    dbg_print(
647 						MSG_ORIG(MSG_UNW_FDEAUXLSDA),
648 						val);
649 					}
650 				}
651 				if ((fdelength + 4) > ndx) {
652 					uint_t	    cnt;
653 					dbg_printf(MSG_ORIG(MSG_UNW_FDECFI));
654 					cnt = 0;
655 					while (ndx < (fdelength + 4)) {
656 						if ((cnt++ % 8) == 0) {
657 						    dbg_printf(
658 						    MSG_ORIG(MSG_UNW_FDECFI1));
659 						}
660 						dbg_printf(
661 						MSG_ORIG(MSG_UNW_FDECFI2),
662 						data[off + ndx++]);
663 					}
664 					dbg_print(MSG_ORIG(MSG_STR_EMPTY));
665 				}
666 
667 				off += fdelength + 4;
668 			}
669 		}
670 	}
671 }
672 
673 /*
674  * Print the hardware/software capabilities.  For executables and shared objects
675  * this should be accompanied with a program header.
676  */
677 static void
678 cap(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
679     GElf_Ehdr *ehdr, Elf *elf)
680 {
681 	GElf_Word	cnt;
682 	GElf_Shdr *	cshdr = 0;
683 	Cache *		ccache;
684 	Elf64_Off	cphdr_off = 0;
685 	Elf64_Xword	cphdr_sz;
686 
687 	/*
688 	 * Determine if a hardware/software capabilities header exists.
689 	 */
690 	for (cnt = 0; cnt < phnum; cnt++) {
691 		GElf_Phdr	phdr;
692 
693 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
694 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
695 			return;
696 		}
697 
698 		if (phdr.p_type == PT_SUNWCAP) {
699 			cphdr_off = phdr.p_offset;
700 			cphdr_sz = phdr.p_filesz;
701 			break;
702 		}
703 	}
704 
705 	/*
706 	 * Determine if a hardware/software capabilities section exists.
707 	 */
708 	for (cnt = 1; cnt < shnum; cnt++) {
709 		Cache *		_cache;
710 		GElf_Shdr	*shdr;
711 
712 		_cache = &cache[cnt];
713 		shdr = &_cache->c_shdr;
714 
715 		if (shdr->sh_type != SHT_SUNW_cap)
716 			continue;
717 
718 		if (cphdr_off && ((cphdr_off < shdr->sh_offset) ||
719 		    (cphdr_off + cphdr_sz) > (shdr->sh_offset + shdr->sh_size)))
720 			continue;
721 
722 		ccache = _cache;
723 		cshdr = shdr;
724 		break;
725 	}
726 
727 	if ((cshdr == 0) && (cphdr_off == 0))
728 		return;
729 
730 	/*
731 	 * Print the hardware/software capabilities section.
732 	 */
733 	if (cshdr) {
734 		GElf_Word	ndx, capn;
735 
736 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
737 		dbg_print(MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name);
738 
739 		Gelf_cap_title();
740 
741 		/* LINTED */
742 		capn = (GElf_Word)(cshdr->sh_size / cshdr->sh_entsize);
743 
744 		/* LINTED */
745 		for (ndx = 0; ndx < capn; ndx++) {
746 			GElf_Cap	cap;
747 
748 			if (gelf_getcap(ccache->c_data, ndx, &cap) == NULL) {
749 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADCAP),
750 				    file, ccache->c_name, elf_errmsg(0));
751 				(void) fflush(stderr);
752 				return;
753 			}
754 			if (cap.c_tag != CA_SUNW_NULL)
755 				Gelf_cap_print(&cap, ndx, ehdr->e_machine);
756 		}
757 	} else
758 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP1), file);
759 
760 	/*
761 	 * If this object is an executable or shared object, then the
762 	 * hardware/software capabilities section should have an accompanying
763 	 * program header.
764 	 */
765 	if (cshdr && ((ehdr->e_type == ET_EXEC) || (ehdr->e_type == ET_DYN))) {
766 		if (cphdr_off == 0)
767 			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP2),
768 			    file, ccache->c_name);
769 		else if ((cphdr_off != cshdr->sh_offset) ||
770 		    (cphdr_sz != cshdr->sh_size))
771 			(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVCAP3),
772 			    file, ccache->c_name);
773 	}
774 }
775 
776 /*
777  * Print the interpretor.
778  */
779 static void
780 interp(const char *file, Cache *cache, GElf_Word shnum, GElf_Word phnum,
781     GElf_Ehdr *ehdr, Elf *elf)
782 {
783 	GElf_Word	cnt;
784 	GElf_Shdr *	ishdr = 0;
785 	Cache *		icache;
786 	Elf64_Off	iphdr_off = 0;
787 	Elf64_Xword	iphdr_sz;
788 
789 	/*
790 	 * Determine if an interp header exists.
791 	 */
792 	for (cnt = 0; cnt < phnum; cnt++) {
793 		GElf_Phdr	phdr;
794 
795 		if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
796 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
797 			return;
798 		}
799 
800 		if (phdr.p_type == PT_INTERP) {
801 			iphdr_off = phdr.p_offset;
802 			iphdr_sz = phdr.p_filesz;
803 			break;
804 		}
805 	}
806 
807 	if (iphdr_off == 0)
808 		return;
809 
810 	/*
811 	 * Determine if an interp section exists.
812 	 */
813 	for (cnt = 1; cnt < shnum; cnt++) {
814 		Cache *		_cache;
815 		GElf_Shdr	*shdr;
816 
817 		_cache = &cache[cnt];
818 		shdr = &_cache->c_shdr;
819 
820 		/*
821 		 * Scan sections to find a section which contains the PT_INTERP
822 		 * string.  The target section can't be in a NOBITS section.
823 		 */
824 		if ((shdr->sh_type == SHT_NOBITS) ||
825 		    (iphdr_off < shdr->sh_offset) ||
826 		    (iphdr_off + iphdr_sz) > (shdr->sh_offset + shdr->sh_size))
827 			continue;
828 
829 		icache = _cache;
830 		ishdr = shdr;
831 		break;
832 	}
833 
834 	/*
835 	 * Print the interpreter string based on the offset defined in the
836 	 * program header, as this is the offset used by the kernel.
837 	 */
838 	if (ishdr) {
839 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
840 		dbg_print(MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name);
841 		dbg_print(MSG_ORIG(MSG_FMT_INDENT),
842 		    (char *)icache->c_data->d_buf +
843 		    (iphdr_off - ishdr->sh_offset));
844 	} else
845 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file);
846 
847 	/*
848 	 * If there are any inconsistences between the program header and
849 	 * section information, flag them.
850 	 */
851 	if (ishdr && ((iphdr_off != ishdr->sh_offset) ||
852 	    (iphdr_sz != ishdr->sh_size))) {
853 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file,
854 		    icache->c_name);
855 		(void) fflush(stderr);
856 	}
857 }
858 
859 /*
860  * Print the syminfo section.
861  */
862 static void
863 syminfo(Cache *cache, GElf_Word shnum, const char *file)
864 {
865 	GElf_Shdr	*shdr;
866 	Elf_Data	*dsyms, *ddyn;
867 	GElf_Word	symn, cnt, ndx;
868 	Cache		*syminfo = 0;
869 	char		*sname;
870 
871 	for (cnt = 1; cnt < shnum; cnt++) {
872 		if (cache[cnt].c_shdr.sh_type == SHT_SUNW_syminfo) {
873 			syminfo = &cache[cnt];
874 			break;
875 		}
876 	}
877 	if (syminfo == 0)
878 		return;
879 
880 	shdr = &syminfo->c_shdr;
881 	/*
882 	 * Determine the symbol info data and number.
883 	 */
884 	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
885 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
886 		    file, syminfo->c_name);
887 		(void) fflush(stderr);
888 		return;
889 	}
890 	/* LINTED */
891 	symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize);
892 
893 	/*
894 	 * Get the data buffer of the associated dynamic section.
895 	 */
896 	if ((shdr->sh_info == 0) || (shdr->sh_info >= shnum)) {
897 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
898 		    file, syminfo->c_name, EC_XWORD(shdr->sh_info));
899 		(void) fflush(stderr);
900 		return;
901 	}
902 	ddyn = cache[shdr->sh_info].c_data;
903 	if (ddyn->d_buf == 0) {
904 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
905 		    file, cache[shdr->sh_info].c_name);
906 		(void) fflush(stderr);
907 		return;
908 	}
909 
910 	/*
911 	 * Get the data buffer of the associated symbol table.
912 	 */
913 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
914 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
915 		    file, syminfo->c_name, EC_XWORD(shdr->sh_link));
916 		(void) fflush(stderr);
917 		return;
918 	}
919 	dsyms = cache[shdr->sh_link].c_data;
920 	if (dsyms->d_buf == 0) {
921 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
922 		    file, cache[shdr->sh_link].c_name);
923 		(void) fflush(stderr);
924 		return;
925 	}
926 
927 	sname = cache[shdr->sh_link].c_name;
928 	shdr = &cache[shdr->sh_link].c_shdr;
929 	/*
930 	 * Get the associated string table section.
931 	 */
932 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
933 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
934 		    file, sname, EC_XWORD(shdr->sh_link));
935 		(void) fflush(stderr);
936 		return;
937 	}
938 
939 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
940 	dbg_print(MSG_INTL(MSG_ELF_SCN_SYMINFO), syminfo->c_name);
941 	Gelf_syminfo_title();
942 
943 	for (ndx = 1; ndx < symn; ndx++) {
944 		GElf_Syminfo 	gsip;
945 		GElf_Sym 	gsym;
946 		GElf_Dyn	gdyn;
947 		const char	*needed, *sname;
948 
949 		if (gelf_getsyminfo(syminfo->c_data, ndx, &gsip) == 0) {
950 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_SIBADCOUNT),
951 			    file, syminfo->c_name, ndx);
952 			(void) fflush(stderr);
953 			return;
954 		}
955 		if ((gsip.si_flags == 0) && (gsip.si_boundto == 0))
956 			continue;
957 
958 		if (gelf_getsym(dsyms, ndx, &gsym) == 0) {
959 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM),
960 			    file, syminfo->c_name, elf_errmsg(0));
961 			(void) fflush(stderr);
962 			return;
963 		}
964 
965 		sname = string(syminfo, cnt, &cache[shdr->sh_link], file,
966 		    gsym.st_name);
967 		needed = 0;
968 
969 		if (gsip.si_boundto < SYMINFO_BT_LOWRESERVE) {
970 			if (gelf_getdyn(ddyn, gsip.si_boundto, &gdyn) == 0) {
971 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADDYN),
972 				    file, syminfo->c_name, gsip.si_boundto);
973 				(void) fflush(stderr);
974 				return;
975 			}
976 			needed = string(syminfo, gsip.si_boundto,
977 			    &cache[shdr->sh_link], file, gdyn.d_un.d_val);
978 		}
979 
980 		Gelf_syminfo_entry(ndx, &gsip, sname, needed);
981 	}
982 }
983 
984 /*
985  * Print version definition section entries.
986  */
987 static void
988 version_def(GElf_Verdef *vdf, GElf_Word shnum, Cache *vcache, Cache *scache,
989     const char *file)
990 {
991 	GElf_Word	cnt;
992 	char		index[MAXNDXSIZE];
993 
994 	Gelf_ver_def_title();
995 
996 	for (cnt = 1; cnt <= shnum; cnt++,
997 	    vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
998 
999 		GElf_Half	vcnt = vdf->vd_cnt - 1;
1000 		GElf_Half	ndx = vdf->vd_ndx;
1001 		GElf_Verdaux	*vdap = (GElf_Verdaux *)
1002 				    ((uintptr_t)vdf + vdf->vd_aux);
1003 		const char	*name, *dep;
1004 
1005 		/*
1006 		 * Obtain the name and first dependency (if any).
1007 		 */
1008 		name = string(vcache, cnt, scache, file, vdap->vda_name);
1009 		vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next);
1010 		if (vcnt)
1011 			dep = string(vcache, cnt, scache, file, vdap->vda_name);
1012 		else
1013 			dep = MSG_ORIG(MSG_STR_EMPTY);
1014 
1015 		(void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX),
1016 		    EC_XWORD(ndx));
1017 		Gelf_ver_line_1(index, name, dep,
1018 		    conv_verflg_str(vdf->vd_flags));
1019 
1020 		/*
1021 		 * Print any additional dependencies.
1022 		 */
1023 		if (vcnt) {
1024 			vdap = (GElf_Verdaux *)((uintptr_t)vdap +
1025 				vdap->vda_next);
1026 			for (vcnt--; vcnt; vcnt--,
1027 			    vdap = (GElf_Verdaux *)((uintptr_t)vdap +
1028 			    vdap->vda_next)) {
1029 				dep = string(vcache, cnt, scache, file,
1030 				    vdap->vda_name);
1031 				Gelf_ver_line_2(MSG_ORIG(MSG_STR_EMPTY), dep);
1032 			}
1033 		}
1034 	}
1035 }
1036 
1037 /*
1038  * Print a version needed section entries.
1039  */
1040 static void
1041 version_need(GElf_Verneed *vnd, GElf_Word shnum, Cache *vcache, Cache *scache,
1042     const char *file)
1043 {
1044 	GElf_Word	cnt;
1045 
1046 	Gelf_ver_need_title();
1047 
1048 	for (cnt = 1; cnt <= shnum; cnt++,
1049 	    vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
1050 
1051 		GElf_Half	vcnt = vnd->vn_cnt;
1052 		GElf_Vernaux	*vnap = (GElf_Vernaux *)((uintptr_t)vnd +
1053 			vnd->vn_aux);
1054 		const char	*name, *dep;
1055 
1056 		/*
1057 		 * Obtain the name of the needed file and the version name
1058 		 * within it that we're dependent on.  Note that the count
1059 		 * should be at least one, otherwise this is a pretty bogus
1060 		 * entry.
1061 		 */
1062 		name = string(vcache, cnt, scache, file, vnd->vn_file);
1063 		if (vcnt)
1064 			dep = string(vcache, cnt, scache, file, vnap->vna_name);
1065 		else
1066 			dep = MSG_INTL(MSG_STR_NULL);
1067 
1068 		Gelf_ver_line_1(MSG_ORIG(MSG_STR_EMPTY), name, dep,
1069 		    conv_verflg_str(vnap->vna_flags));
1070 
1071 		/*
1072 		 * Print any additional version dependencies.
1073 		 */
1074 		if (vcnt) {
1075 			vnap = (GElf_Vernaux *)((uintptr_t)vnap +
1076 				vnap->vna_next);
1077 			for (vcnt--; vcnt; vcnt--,
1078 			    vnap = (GElf_Vernaux *)((uintptr_t)vnap +
1079 			    vnap->vna_next)) {
1080 				dep = string(vcache, cnt, scache, file,
1081 				    vnap->vna_name);
1082 				Gelf_ver_line_3(MSG_ORIG(MSG_STR_EMPTY), dep,
1083 				    conv_verflg_str(vnap->vna_flags));
1084 			}
1085 		}
1086 	}
1087 }
1088 
1089 /*
1090  * Search for any verion sections - the Versym output is possibly
1091  * used by the symbols() printing.  If VERSYM is specified - then
1092  * display the version information.
1093  */
1094 static Cache *
1095 versions(Cache *cache, GElf_Word shnum, const char *file, uint32_t flags)
1096 {
1097 	GElf_Word	cnt;
1098 	Cache		*versymcache = 0;
1099 
1100 	for (cnt = 1; cnt < shnum; cnt++) {
1101 		void *		ver;
1102 		uint_t		num;
1103 		Cache *		_cache = &cache[cnt];
1104 		GElf_Shdr *	shdr = &_cache->c_shdr;
1105 
1106 		/*
1107 		 * If this is the version symbol table simply record its
1108 		 * data address for possible use in later symbol processing.
1109 		 */
1110 		if (shdr->sh_type == SHT_SUNW_versym) {
1111 			versymcache = _cache;
1112 			continue;
1113 		}
1114 
1115 		if ((flags & FLG_VERSIONS) == 0)
1116 			continue;
1117 
1118 		if ((shdr->sh_type != SHT_SUNW_verdef) &&
1119 		    (shdr->sh_type != SHT_SUNW_verneed))
1120 			continue;
1121 
1122 		/*
1123 		 * Determine the version section data and number.
1124 		 */
1125 		if ((ver = (void *)_cache->c_data->d_buf) == 0) {
1126 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1127 			    file, _cache->c_name);
1128 			(void) fflush(stderr);
1129 			continue;
1130 		}
1131 		if ((num = shdr->sh_info) == 0) {
1132 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
1133 			    file, _cache->c_name, EC_XWORD(shdr->sh_info));
1134 			(void) fflush(stderr);
1135 			continue;
1136 		}
1137 
1138 		/*
1139 		 * Get the data buffer for the associated string table.
1140 		 */
1141 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1142 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1143 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
1144 			(void) fflush(stderr);
1145 			continue;
1146 		}
1147 
1148 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1149 		if (shdr->sh_type == SHT_SUNW_verdef) {
1150 			dbg_print(MSG_INTL(MSG_ELF_SCN_VERDEF),
1151 			    _cache->c_name);
1152 			version_def((GElf_Verdef *)ver, num, _cache,
1153 			    &cache[shdr->sh_link], file);
1154 		} else if (shdr->sh_type == SHT_SUNW_verneed) {
1155 			dbg_print(MSG_INTL(MSG_ELF_SCN_VERNEED),
1156 			    _cache->c_name);
1157 			version_need((GElf_Verneed *)ver, num, _cache,
1158 			    &cache[shdr->sh_link], file);
1159 		}
1160 	}
1161 	return (versymcache);
1162 }
1163 
1164 /*
1165  * Search for and process any symbol tables.
1166  */
1167 static void
1168 symbols(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
1169     const char *name, Cache *versymcache, const char *file)
1170 {
1171 	GElf_Word	cnt;
1172 	char		is_core = (ehdr->e_type == ET_CORE);
1173 
1174 	for (cnt = 1; cnt < shnum; cnt++) {
1175 		GElf_Sym 	sym;
1176 		GElf_Word	symn, _cnt;
1177 		GElf_Versym	*versym;
1178 		Cache		*_cache = &cache[cnt];
1179 		GElf_Shdr	*shdr = &_cache->c_shdr;
1180 		Word		*symshndx;
1181 		uint_t		nosymshndx;
1182 		uint_t		nosyminshndx;
1183 
1184 		if ((shdr->sh_type != SHT_SYMTAB) &&
1185 		    (shdr->sh_type != SHT_DYNSYM))
1186 			continue;
1187 		if (name && strcmp(name, _cache->c_name))
1188 			continue;
1189 
1190 		/*
1191 		 * Determine the symbol data and number.
1192 		 */
1193 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
1194 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1195 			    file, _cache->c_name);
1196 			(void) fflush(stderr);
1197 			continue;
1198 		}
1199 		/* LINTED */
1200 		symn = (GElf_Word)(shdr->sh_size / shdr->sh_entsize);
1201 
1202 		/*
1203 		 * Get the associated string table section.
1204 		 */
1205 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1206 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1207 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
1208 			(void) fflush(stderr);
1209 			continue;
1210 		}
1211 
1212 		/*
1213 		 * Determine if there is a associated Versym section
1214 		 * with this Symbol Table.
1215 		 */
1216 		if (versymcache && (versymcache->c_shdr.sh_link == cnt))
1217 			versym = versymcache->c_data->d_buf;
1218 		else
1219 			versym = 0;
1220 
1221 		/*
1222 		 * Loop through the symbol tables entries.
1223 		 */
1224 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1225 		dbg_print(MSG_INTL(MSG_ELF_SCN_SYMTAB), _cache->c_name);
1226 		Gelf_sym_table_title(ehdr, MSG_INTL(MSG_STR_INDEX),
1227 		    MSG_INTL(MSG_STR_NAME));
1228 
1229 		symshndx = 0;
1230 		nosymshndx = 0;
1231 		nosyminshndx = 0;
1232 		for (_cnt = 0; _cnt < symn; _cnt++) {
1233 			char		index[MAXNDXSIZE];
1234 			char		*sec;
1235 			const char	*sname;
1236 			int		verndx;
1237 			uchar_t		type;
1238 			GElf_Shdr	*tshdr;
1239 			Word		shndx;
1240 
1241 			if (gelf_getsym(_cache->c_data, _cnt, &sym) == NULL) {
1242 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSYM),
1243 				    file, _cache->c_name, elf_errmsg(0));
1244 				(void) fflush(stderr);
1245 				break;
1246 			}
1247 
1248 			/*
1249 			 * If we are using extended symbol indexes, find the
1250 			 * corresponding SHN_SYMTAB_SHNDX table.
1251 			 */
1252 			if ((sym.st_shndx == SHN_XINDEX) &&
1253 			    (symshndx == 0) && (nosymshndx == 0)) {
1254 				Word	__cnt;
1255 
1256 				for (__cnt = 1; __cnt < shnum; __cnt++) {
1257 					Cache		*_cache = &cache[__cnt];
1258 					GElf_Shdr	*shdr = &_cache->c_shdr;
1259 
1260 					if ((shdr->sh_type !=
1261 					    SHT_SYMTAB_SHNDX) ||
1262 					    (shdr->sh_link != cnt))
1263 						continue;
1264 					if (shdr->sh_entsize)
1265 						/* LINTED */
1266 						nosyminshndx = (uint_t)
1267 						shdr->sh_size/shdr->sh_entsize;
1268 					if (nosyminshndx == 0)
1269 						continue;
1270 					symshndx = _cache->c_data->d_buf;
1271 					break;
1272 				}
1273 				if (symshndx == 0)
1274 					nosymshndx = 1;
1275 			}
1276 
1277 			/* LINTED */
1278 			sname = string(_cache, _cnt, &cache[shdr->sh_link],
1279 			    file, sym.st_name);
1280 
1281 			tshdr = 0;
1282 			sec = NULL;
1283 
1284 			if (is_core)
1285 				sec = (char *)MSG_INTL(MSG_STR_UNKNOWN);
1286 			else if ((sym.st_shndx < SHN_LORESERVE) &&
1287 			    (sym.st_shndx < shnum)) {
1288 				shndx = sym.st_shndx;
1289 				tshdr = &(cache[shndx].c_shdr);
1290 				sec = cache[shndx].c_name;
1291 			} else if (sym.st_shndx == SHN_XINDEX) {
1292 				if (symshndx) {
1293 					Word	_symshndx;
1294 
1295 					if (_cnt > nosyminshndx) {
1296 					    (void) fprintf(stderr,
1297 						MSG_INTL(MSG_ERR_BADSYMXINDEX1),
1298 						file, _cache->c_name,
1299 						EC_WORD(_cnt));
1300 					    (void) fflush(stderr);
1301 					} else if ((_symshndx =
1302 					    symshndx[_cnt]) > shnum) {
1303 					    (void) fprintf(stderr,
1304 						MSG_INTL(MSG_ERR_BADSYMXINDEX2),
1305 						file, _cache->c_name,
1306 						EC_WORD(_cnt),
1307 						EC_WORD(_symshndx));
1308 					    (void) fflush(stderr);
1309 					} else {
1310 					    shndx = _symshndx;
1311 					    tshdr = &(cache[shndx].c_shdr);
1312 					    sec = cache[shndx].c_name;
1313 					}
1314 				} else {
1315 					(void) fprintf(stderr,
1316 						MSG_INTL(MSG_ERR_BADSYMXINDEX3),
1317 						file, _cache->c_name,
1318 						EC_WORD(_cnt));
1319 					(void) fflush(stderr);
1320 				}
1321 			} else if ((sym.st_shndx < SHN_LORESERVE) &&
1322 			    (sym.st_shndx >= shnum)) {
1323 				(void) fprintf(stderr,
1324 					MSG_INTL(MSG_ERR_BADSYM5),
1325 					file, _cache->c_name,
1326 					sname, sym.st_shndx);
1327 				(void) fflush(stderr);
1328 			}
1329 
1330 			/*
1331 			 * If versioning is available display the
1332 			 * version index.
1333 			 */
1334 			if (versym)
1335 				verndx = (int)versym[_cnt];
1336 			else
1337 				verndx = 0;
1338 
1339 			/*
1340 			 * Error checking for TLS.
1341 			 */
1342 			type = ELF_ST_TYPE(sym.st_info);
1343 			if (type == STT_TLS) {
1344 				if (tshdr &&
1345 				    (sym.st_shndx != SHN_UNDEF) &&
1346 				    ((tshdr->sh_flags & SHF_TLS) == 0)) {
1347 					(void) fprintf(stderr,
1348 					    MSG_INTL(MSG_ERR_BADSYM3), file,
1349 					    _cache->c_name, sname);
1350 					(void) fflush(stderr);
1351 				}
1352 			} else if ((type != STT_SECTION) && sym.st_size &&
1353 			    tshdr && (tshdr->sh_flags & SHF_TLS)) {
1354 				(void) fprintf(stderr,
1355 				    MSG_INTL(MSG_ERR_BADSYM4), file,
1356 				    _cache->c_name, sname);
1357 				(void) fflush(stderr);
1358 			}
1359 
1360 			/*
1361 			 * If a symbol has size, then make sure the section it
1362 			 * references is appropriate.  Note, UNDEF symbols that
1363 			 * have a size, have been known to exist - ignore them.
1364 			 */
1365 			if (sym.st_size && shndx && tshdr &&
1366 			    (tshdr->sh_size < sym.st_size)) {
1367 				(void) fprintf(stderr,
1368 				    MSG_INTL(MSG_ERR_BADSYM6), file,
1369 				    _cache->c_name, sname, EC_WORD(shndx),
1370 				    EC_XWORD(tshdr->sh_size),
1371 				    EC_XWORD(sym.st_size));
1372 				(void) fflush(stderr);
1373 			}
1374 
1375 			(void) snprintf(index, MAXNDXSIZE,
1376 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(_cnt));
1377 
1378 			Gelf_sym_table_entry(index, ehdr, &sym, verndx, sec,
1379 			    sname);
1380 		}
1381 	}
1382 }
1383 
1384 /*
1385  * Search for and process any relocation sections.
1386  */
1387 static void
1388 reloc(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
1389     const char *name, const char *file, uint32_t flags)
1390 {
1391 	GElf_Word	cnt;
1392 
1393 	for (cnt = 1; cnt < shnum; cnt++) {
1394 		Word		type;
1395 		ulong_t		numrels, entsize;
1396 		int		ndx;
1397 		Elf_Data	*dsyms;
1398 		Cache		*_cache = &cache[cnt];
1399 		GElf_Shdr	*shdr = &_cache->c_shdr;
1400 		char		*sname;
1401 
1402 		if (((type = shdr->sh_type) != SHT_RELA) &&
1403 		    (type != SHT_REL))
1404 			continue;
1405 		if (name && strcmp(name, _cache->c_name))
1406 			continue;
1407 
1408 		/*
1409 		 * Decide entry size
1410 		 */
1411 		if (((entsize = shdr->sh_entsize) == 0) ||
1412 		    (entsize > shdr->sh_size)) {
1413 			if (type == SHT_RELA)
1414 				entsize = sizeof (GElf_Rela);
1415 			else
1416 				entsize = sizeof (GElf_Rel);
1417 		}
1418 
1419 		/*
1420 		 * Determine the number of relocations available.
1421 		 */
1422 		if (shdr->sh_size == 0) {
1423 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1424 			    file, _cache->c_name);
1425 			(void) fflush(stderr);
1426 			continue;
1427 		}
1428 		numrels = shdr->sh_size / entsize;
1429 
1430 		/*
1431 		 * Get the data buffer for the associated symbol table.  Note
1432 		 * that we've been known to create static binaries containing
1433 		 * relocations against weak symbols, if these get stripped the
1434 		 * relocation records can't make symbolic references.
1435 		 */
1436 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1437 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1438 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
1439 			(void) fflush(stderr);
1440 			continue;
1441 		}
1442 		dsyms = cache[shdr->sh_link].c_data;
1443 		if (dsyms->d_buf == 0) {
1444 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1445 			    file, cache[shdr->sh_link].c_name);
1446 			(void) fflush(stderr);
1447 			continue;
1448 		}
1449 
1450 		sname = cache[shdr->sh_link].c_name;
1451 		shdr = &cache[shdr->sh_link].c_shdr;
1452 		/*
1453 		 * Get the associated string table section.
1454 		 */
1455 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1456 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1457 			    file, sname, EC_XWORD(shdr->sh_link));
1458 			(void) fflush(stderr);
1459 			continue;
1460 		}
1461 
1462 		/*
1463 		 * Loop through the relocation entries.
1464 		 */
1465 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1466 		dbg_print(MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name);
1467 		if (type == SHT_RELA) {
1468 			if (flags & FLG_LONGNAME)
1469 				dbg_print(MSG_INTL(MSG_ELF_L_RELOC_RELA));
1470 			else
1471 				dbg_print(MSG_INTL(MSG_ELF_RELOC_RELA));
1472 		} else {
1473 			if (flags & FLG_LONGNAME)
1474 				dbg_print(MSG_INTL(MSG_ELF_L_RELOC_REL));
1475 			else
1476 				dbg_print(MSG_INTL(MSG_ELF_RELOC_REL));
1477 		}
1478 
1479 		/* LINTED */
1480 		for (ndx = 0; ndx < numrels; ndx++) {
1481 			char		section[BUFSIZ];
1482 			const char	*_name;
1483 			GElf_Word	sndx;
1484 			ulong_t		r_type;
1485 			GElf_Sym	_sym;
1486 			GElf_Rela	rela;
1487 
1488 			/*
1489 			 * Determine the symbol with which this relocation is
1490 			 * associated.  If the symbol represents a section
1491 			 * offset construct an appropriate string.
1492 			 */
1493 			if (type == SHT_RELA) {
1494 				(void) gelf_getrela(_cache->c_data, ndx,
1495 				    &rela);
1496 			} else {
1497 				(void) gelf_getrel(_cache->c_data, ndx,
1498 				    (GElf_Rel*)&rela);
1499 			}
1500 			/* LINTED */
1501 			sndx = (GElf_Word)GELF_R_SYM(rela.r_info);
1502 			r_type = GELF_R_TYPE(rela.r_info);
1503 
1504 			/* LINTED */
1505 			if (gelf_getsym(dsyms, (int)sndx, &_sym) == NULL) {
1506 				(void) fprintf(stderr,
1507 					MSG_INTL(MSG_ERR_RELBADSYMNDX),
1508 				    file, elf_errmsg(0));
1509 				(void) fflush(stderr);
1510 				_name = MSG_INTL(MSG_STR_UNKNOWN);
1511 			} else  {
1512 				if ((GELF_ST_TYPE(_sym.st_info) ==
1513 				    STT_SECTION) && (_sym.st_name == 0)) {
1514 					if (flags & FLG_LONGNAME)
1515 					    (void) snprintf(section, BUFSIZ,
1516 						MSG_INTL(MSG_STR_L_SECTION),
1517 						cache[_sym.st_shndx].c_name);
1518 					else
1519 					    (void) snprintf(section, BUFSIZ,
1520 						MSG_INTL(MSG_STR_SECTION),
1521 						cache[_sym.st_shndx].c_name);
1522 					_name = (const char *)section;
1523 				} else {
1524 					/* LINTED */
1525 					_name = string(_cache,
1526 					    sndx, &cache[shdr->sh_link],
1527 					    file, _sym.st_name);
1528 				}
1529 			}
1530 
1531 			if ((sndx == 0) && ((IAM_SPARC(ehdr->e_machine) &&
1532 			    ((r_type != R_SPARC_NONE) &&
1533 			    (r_type != R_SPARC_REGISTER) &&
1534 			    (r_type != R_SPARC_RELATIVE))) ||
1535 			    ((IAM_INTEL(ehdr->e_machine) &&
1536 			    ((r_type != R_386_NONE) &&
1537 			    (r_type != R_386_RELATIVE)))))) {
1538 				(void) fprintf(stderr,
1539 				    MSG_INTL(MSG_ERR_BADREL1), file,
1540 				    conv_reloc_type_str(ehdr->e_machine,
1541 				    /* LINTED */
1542 				    (uint_t)r_type));
1543 				(void) fflush(stderr);
1544 			}
1545 
1546 			Gelf_reloc_entry(MSG_ORIG(MSG_STR_EMPTY),
1547 			    ehdr->e_machine, type, (void *)&rela,
1548 			    _cache->c_name, _name);
1549 		}
1550 	}
1551 }
1552 
1553 /*
1554  * Search for and process a .dynamic section.
1555  */
1556 static void
1557 dynamic(Cache *cache, GElf_Word shnum, GElf_Ehdr *ehdr, const char *file)
1558 {
1559 	GElf_Word	cnt;
1560 
1561 	for (cnt = 1; cnt < shnum; cnt++) {
1562 		GElf_Dyn	dyn;
1563 		ulong_t		numdyn;
1564 		int		ndx;
1565 		Cache *		_cache = &cache[cnt];
1566 		GElf_Shdr *	shdr = &_cache->c_shdr;
1567 
1568 		if (shdr->sh_type != SHT_DYNAMIC)
1569 			continue;
1570 
1571 		/*
1572 		 * Get the associated string table section.
1573 		 */
1574 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1575 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1576 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
1577 			(void) fflush(stderr);
1578 			continue;
1579 		}
1580 		numdyn = shdr->sh_size / shdr->sh_entsize;
1581 
1582 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1583 		dbg_print(MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name);
1584 
1585 		Gelf_dyn_title();
1586 
1587 		/* LINTED */
1588 		for (ndx = 0; ndx < numdyn; ++ndx) {
1589 			const char	*name;
1590 
1591 			(void) gelf_getdyn(_cache->c_data, ndx, &dyn);
1592 			if (dyn.d_tag == DT_NULL)
1593 				break;
1594 
1595 			/*
1596 			 * Print the information numerically, and if possible
1597 			 * as a string.
1598 			 */
1599 			if ((dyn.d_tag == DT_NEEDED) ||
1600 			    (dyn.d_tag == DT_SONAME) ||
1601 			    (dyn.d_tag == DT_FILTER) ||
1602 			    (dyn.d_tag == DT_AUXILIARY) ||
1603 			    (dyn.d_tag == DT_CONFIG) ||
1604 			    (dyn.d_tag == DT_RPATH) ||
1605 			    (dyn.d_tag == DT_RUNPATH) ||
1606 			    (dyn.d_tag == DT_USED) ||
1607 			    (dyn.d_tag == DT_DEPAUDIT) ||
1608 			    (dyn.d_tag == DT_AUDIT) ||
1609 			    (dyn.d_tag == DT_SUNW_AUXILIARY) ||
1610 			    (dyn.d_tag == DT_SUNW_FILTER))
1611 				name = string(_cache, ndx,
1612 				    &cache[shdr->sh_link], file,
1613 				    dyn.d_un.d_ptr);
1614 			else if (dyn.d_tag == DT_FLAGS)
1615 			    /* LINTED */
1616 			    name = conv_dynflag_str((Word)dyn.d_un.d_val);
1617 			else if (dyn.d_tag == DT_FLAGS_1)
1618 			    /* LINTED */
1619 			    name = conv_dynflag_1_str((Word)dyn.d_un.d_val);
1620 			else if (dyn.d_tag == DT_POSFLAG_1)
1621 			    /* LINTED */
1622 			    name = conv_dynposflag_1_str((Word)dyn.d_un.d_val);
1623 			else if (dyn.d_tag == DT_FEATURE_1)
1624 			    /* LINTED */
1625 			    name = conv_dynfeature_1_str((Word)dyn.d_un.d_val);
1626 			else if (dyn.d_tag == DT_DEPRECATED_SPARC_REGISTER)
1627 			    name = MSG_INTL(MSG_STR_DEPRECATED);
1628 			else
1629 			    name = MSG_ORIG(MSG_STR_EMPTY);
1630 
1631 			Gelf_dyn_print(&dyn, ndx, name, ehdr->e_machine);
1632 		}
1633 	}
1634 }
1635 
1636 /*
1637  * Search for and process a MOVE section.
1638  */
1639 static void
1640 move(Cache *cache, GElf_Word shnum, const char *name, const char *file,
1641     uint32_t flags)
1642 {
1643 	GElf_Word	cnt;
1644 
1645 	for (cnt = 1; cnt < shnum; cnt++) {
1646 		ulong_t		num, symn;
1647 		int		ndx;
1648 		Elf_Data	*dsyms;
1649 		const char	*fmt;
1650 		Cache		*_cache = &cache[cnt];
1651 		GElf_Shdr	*shdr = &_cache->c_shdr;
1652 		char		*sname;
1653 
1654 		if (shdr->sh_type != SHT_SUNW_move)
1655 			continue;
1656 		if (name && strcmp(name, _cache->c_name))
1657 			continue;
1658 
1659 		/*
1660 		 * Determine the move data and number.
1661 		 */
1662 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
1663 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1664 			    file, _cache->c_name);
1665 			(void) fflush(stderr);
1666 			continue;
1667 		}
1668 		num = shdr->sh_size / shdr->sh_entsize;
1669 
1670 		/*
1671 		 * Get the data buffer for the associated symbol table.
1672 		 */
1673 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1674 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1675 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
1676 			(void) fflush(stderr);
1677 			continue;
1678 		}
1679 		dsyms = cache[shdr->sh_link].c_data;
1680 		if (dsyms->d_buf == 0) {
1681 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1682 			    file, cache[shdr->sh_link].c_name);
1683 			(void) fflush(stderr);
1684 			continue;
1685 		}
1686 
1687 		sname = cache[shdr->sh_link].c_name;
1688 		shdr = &cache[shdr->sh_link].c_shdr;
1689 
1690 		/*
1691 		 * Get the associated string table section.
1692 		 */
1693 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1694 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1695 			    file, sname, EC_XWORD(shdr->sh_link));
1696 			(void) fflush(stderr);
1697 			continue;
1698 		}
1699 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
1700 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1701 			    file, sname);
1702 			(void) fflush(stderr);
1703 			continue;
1704 		}
1705 		symn = shdr->sh_size / shdr->sh_entsize;
1706 
1707 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1708 		dbg_print(MSG_INTL(MSG_MV_TITLE), _cache->c_name);
1709 
1710 		fmt = MSG_INTL(MSG_MV_ENTRY);
1711 
1712 		/* LINTED */
1713 		for (ndx = 0; ndx < num; ndx++) {
1714 			GElf_Move 	move;
1715 			const char	*name;
1716 			GElf_Sym	sym;
1717 			char		sct[BUFSIZ];
1718 			Word		shndx;
1719 
1720 			if (gelf_getmove(_cache->c_data, ndx, &move) == NULL) {
1721 				(void) fprintf(stderr,
1722 					MSG_INTL(MSG_ERR_BADMOVE),
1723 					file, _cache->c_name, elf_errmsg(0));
1724 				(void) fflush(stderr);
1725 				break;
1726 			}
1727 
1728 			/*
1729 			 * Check for null entries
1730 			 */
1731 			if ((move.m_info == 0) && (move.m_value == 0) &&
1732 			    (move.m_poffset == 0) && (move.m_repeat == 0) &&
1733 			    (move.m_stride == 0)) {
1734 				dbg_print(fmt, EC_XWORD(move.m_poffset),
1735 				    EC_XWORD(0), 0, 0, 0, EC_LWORD(0),
1736 				    MSG_ORIG(MSG_STR_EMPTY));
1737 				continue;
1738 			}
1739 			if ((GELF_M_SYM(move.m_info) == 0) ||
1740 			    (GELF_M_SYM(move.m_info) >= symn)) {
1741 				(void) fprintf(stderr,
1742 				    MSG_INTL(MSG_ERR_BADMINFO), file,
1743 				    _cache->c_name, EC_XWORD(move.m_info));
1744 				(void) fflush(stderr);
1745 				dbg_print(fmt, EC_XWORD(move.m_poffset),
1746 				    EC_XWORD(GELF_M_SYM(move.m_info)),
1747 				    /* LINTED */
1748 				    GELF_M_SIZE(move.m_info), move.m_repeat,
1749 				    move.m_stride, EC_LWORD(move.m_value),
1750 				    MSG_INTL(MSG_STR_UNKNOWN));
1751 				continue;
1752 			}
1753 
1754 			if (gelf_getsym(dsyms,
1755 			    /* LINTED */
1756 			    (int)GELF_M_SYM(move.m_info), &sym) == NULL) {
1757 				(void) fprintf(stderr,
1758 					MSG_INTL(MSG_ERR_MVBADSYMNDX),
1759 				    file, elf_errmsg(0));
1760 				(void) fflush(stderr);
1761 				name = MSG_INTL(MSG_STR_UNKNOWN);
1762 			} else {
1763 				if ((GELF_ST_TYPE(sym.st_info) ==
1764 				    STT_SECTION) && (sym.st_name == 0)) {
1765 				    if (flags & FLG_LONGNAME)
1766 					(void) snprintf(sct, BUFSIZ,
1767 					    MSG_INTL(MSG_STR_L_SECTION),
1768 					    cache[sym.st_shndx].c_name);
1769 				    else
1770 					(void) snprintf(sct, BUFSIZ,
1771 					    MSG_INTL(MSG_STR_SECTION),
1772 					    cache[sym.st_shndx].c_name);
1773 					name = (const char *)sct;
1774 				} else {
1775 					name = demangle(string(_cache,
1776 					    /* LINTED */
1777 					    (GElf_Word)GELF_M_SYM(move.m_info),
1778 					    &cache[shdr->sh_link], file,
1779 					    sym.st_name), flags);
1780 				}
1781 			}
1782 
1783 			/*
1784 			 * Additional sanity check.
1785 			 */
1786 			shndx = sym.st_shndx;
1787 			if (!((shndx == SHN_COMMON) ||
1788 			    (((shndx >= 1) && (shndx <= shnum)) &&
1789 			    (cache[shndx].c_shdr).sh_type == SHT_NOBITS))) {
1790 				(void) fprintf(stderr,
1791 					MSG_INTL(MSG_ERR_BADSYM2), file,
1792 					_cache->c_name, name);
1793 				(void) fflush(stderr);
1794 			}
1795 
1796 			dbg_print(fmt, EC_XWORD(move.m_poffset),
1797 			    EC_XWORD(GELF_M_SYM(move.m_info)),
1798 			    /* LINTED */
1799 			    GELF_M_SIZE(move.m_info), move.m_repeat,
1800 			    move.m_stride, EC_LWORD(move.m_value), name);
1801 		}
1802 	}
1803 }
1804 
1805 /*
1806  * Traverse a note section analyzing each note information block.
1807  * The data buffers size is used to validate references before they are made,
1808  * and is decremented as each element is processed.
1809  */
1810 void
1811 note_entry(Cache *cache, Word *data, Word size, const char *file)
1812 {
1813 	Word	bsize = size;
1814 	/*
1815 	 * Print out a single `note' information block.
1816 	 */
1817 	while (size > 0) {
1818 		Word	namesz, descsz, type, pad, noteoff;
1819 
1820 
1821 		noteoff = bsize - size;
1822 		/*
1823 		 * Make sure we can at least reference the 3 initial entries
1824 		 * (4-byte words) of the note information block.
1825 		 */
1826 		if (size >= (Word)(sizeof (Word) * 3))
1827 			size -= (Word)(sizeof (Word) * 3);
1828 		else {
1829 			(void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASIZE),
1830 				file, cache->c_name, EC_WORD(noteoff));
1831 			(void) fflush(stderr);
1832 			return;
1833 		}
1834 
1835 		/*
1836 		 * Make sure any specified name string can be referenced.
1837 		 */
1838 		if ((namesz = *data++) != 0) {
1839 			if (size >= namesz)
1840 				size -= namesz;
1841 			else {
1842 				(void) fprintf(stderr,
1843 					MSG_INTL(MSG_NOTE_BADNMSIZE),
1844 					file, cache->c_name, EC_WORD(noteoff),
1845 					EC_WORD(namesz));
1846 				(void) fflush(stderr);
1847 				return;
1848 			}
1849 		}
1850 		/*
1851 		 * Make sure any specified descriptor can be referenced.
1852 		 */
1853 		if ((descsz = *data++) != 0) {
1854 			/*
1855 			 * If namesz isn't a 4-byte multiple, account for any
1856 			 * padding that must exist before the descriptor.
1857 			 */
1858 			if ((pad = (namesz & (Word)(sizeof (Word) - 1))) != 0) {
1859 				pad = (Word)sizeof (Word) - pad;
1860 				size -= pad;
1861 			}
1862 			if (size >= descsz)
1863 				size -= descsz;
1864 			else {
1865 				(void) fprintf(stderr,
1866 					MSG_INTL(MSG_NOTE_BADDESIZE),
1867 					file, cache->c_name, EC_WORD(noteoff),
1868 					EC_WORD(namesz));
1869 				(void) fflush(stderr);
1870 				return;
1871 			}
1872 		}
1873 
1874 		type = *data++;
1875 
1876 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1877 		dbg_print(MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type));
1878 
1879 		dbg_print(MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz));
1880 		if (namesz) {
1881 			char	*name = (char *)data;
1882 
1883 			/*
1884 			 * Since the name string may have 'null' bytes
1885 			 * in it (ia32 .string) - we just write the
1886 			 * whole stream in a single fwrite.
1887 			 */
1888 			(void) fwrite(name, namesz, 1, stdout);
1889 			name = name + ((namesz + (sizeof (Word) - 1)) &
1890 			    ~(sizeof (Word) - 1));
1891 			/* LINTED */
1892 			data = (Word *)name;
1893 			dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1894 		}
1895 
1896 		/*
1897 		 * If multiple information blocks exist within a .note section
1898 		 * account for any padding that must exist before the next
1899 		 * information block.
1900 		 */
1901 		if ((pad = (descsz & (Word)(sizeof (Word) - 1))) != 0) {
1902 			pad = (Word)sizeof (Word) - pad;
1903 			if (size > pad)
1904 				size -= pad;
1905 		}
1906 
1907 		dbg_print(MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz));
1908 		if (descsz) {
1909 			int		ndx, byte, word;
1910 			char		string[58], * str = string;
1911 			uchar_t		*desc = (uchar_t *)data;
1912 
1913 			/*
1914 			 * Dump descriptor bytes.
1915 			 */
1916 			for (ndx = byte = word = 0; descsz; descsz--, desc++) {
1917 				int	tok = *desc;
1918 
1919 				(void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK),
1920 				    tok);
1921 				str += 3;
1922 
1923 				if (++byte == 4) {
1924 					*str++ = ' ', *str++ = ' ';
1925 					word++;
1926 					byte = 0;
1927 				}
1928 				if (word == 4) {
1929 					*str = '\0';
1930 					dbg_print(MSG_ORIG(MSG_NOTE_DESC),
1931 					    ndx, string);
1932 					word = 0;
1933 					ndx += 16;
1934 					str = string;
1935 				}
1936 			}
1937 			if (byte || word) {
1938 				*str = '\0';
1939 				dbg_print(MSG_ORIG(MSG_NOTE_DESC), ndx, string);
1940 			}
1941 
1942 			desc += pad;
1943 			/* LINTED */
1944 			data = (Word *)desc;
1945 		}
1946 	}
1947 }
1948 
1949 /*
1950  * Search for and process a .note section.
1951  */
1952 static void
1953 note(Cache *cache, GElf_Word shnum, const char *name, const char *file)
1954 {
1955 	GElf_Word	cnt;
1956 
1957 	/*
1958 	 * Otherwise look for any .note sections.
1959 	 */
1960 	for (cnt = 1; cnt < shnum; cnt++) {
1961 		Cache *		_cache = &cache[cnt];
1962 		GElf_Shdr *	shdr = &_cache->c_shdr;
1963 
1964 		if (shdr->sh_type != SHT_NOTE)
1965 			continue;
1966 		if (name && strcmp(name, _cache->c_name))
1967 			continue;
1968 
1969 		/*
1970 		 * As these sections are often hand rolled, make sure they're
1971 		 * properly aligned before proceeding.
1972 		 */
1973 		if (shdr->sh_offset & (sizeof (Word) - 1)) {
1974 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN),
1975 			    file, _cache->c_name);
1976 			(void) fflush(stderr);
1977 			continue;
1978 		}
1979 
1980 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
1981 		dbg_print(MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name);
1982 		note_entry(_cache, (Word *)_cache->c_data->d_buf,
1983 		/* LINTED */
1984 		    (Word)_cache->c_data->d_size, file);
1985 	}
1986 }
1987 
1988 
1989 #define	MAXCOUNT	500
1990 
1991 static void
1992 hash(Cache *cache, GElf_Word shnum, const char *name, const char *file,
1993     uint32_t flags)
1994 {
1995 	static int	count[MAXCOUNT];
1996 	GElf_Word	cnt;
1997 	ulong_t		ndx, bkts;
1998 	char		number[MAXNDXSIZE];
1999 
2000 	for (cnt = 1; cnt < shnum; cnt++) {
2001 		uint_t		*hash, *chain;
2002 		Elf_Data	*dsyms;
2003 		Cache		*_cache = &cache[cnt];
2004 		GElf_Shdr	*shdr = &_cache->c_shdr;
2005 		char		*sname;
2006 
2007 		if (shdr->sh_type != SHT_HASH)
2008 			continue;
2009 		if (name && strcmp(name, _cache->c_name))
2010 			continue;
2011 
2012 		/*
2013 		 * Determine the hash table data and size.
2014 		 */
2015 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
2016 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2017 			    file, _cache->c_name);
2018 			(void) fflush(stderr);
2019 			continue;
2020 		}
2021 		hash = (uint_t *)_cache->c_data->d_buf;
2022 		bkts = *hash;
2023 		chain = hash + 2 + bkts;
2024 		hash += 2;
2025 
2026 		/*
2027 		 * Get the data buffer for the associated symbol table.
2028 		 */
2029 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
2030 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2031 			    file, _cache->c_name, EC_XWORD(shdr->sh_link));
2032 			(void) fflush(stderr);
2033 			continue;
2034 		}
2035 		dsyms = cache[shdr->sh_link].c_data;
2036 		if (dsyms->d_buf == 0) {
2037 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2038 			    file, cache[shdr->sh_link].c_name);
2039 			(void) fflush(stderr);
2040 			continue;
2041 		}
2042 
2043 		sname = cache[shdr->sh_link].c_name;
2044 		shdr = &cache[shdr->sh_link].c_shdr;
2045 		/*
2046 		 * Get the associated string table section.
2047 		 */
2048 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
2049 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2050 			    file, sname, EC_XWORD(shdr->sh_link));
2051 			(void) fflush(stderr);
2052 			continue;
2053 		}
2054 
2055 		dbg_print(MSG_ORIG(MSG_STR_EMPTY));
2056 		dbg_print(MSG_INTL(MSG_ELF_SCN_HASH), _cache->c_name);
2057 		dbg_print(MSG_INTL(MSG_ELF_HASH_INFO));
2058 
2059 		/*
2060 		 * Loop through the hash buckets, printing the appropriate
2061 		 * symbols.
2062 		 */
2063 		for (ndx = 0; ndx < bkts; ndx++, hash++) {
2064 			GElf_Sym	_sym;
2065 			const char	*_str;
2066 			GElf_Word	_ndx, _cnt;
2067 			char		_number[MAXNDXSIZE];
2068 			ulong_t		nbkt, nhash;
2069 
2070 			if (*hash == 0) {
2071 				count[0]++;
2072 				continue;
2073 			}
2074 
2075 			/* LINTED */
2076 			if (gelf_getsym(dsyms, (int)*hash, &_sym) == NULL) {
2077 				(void) fprintf(stderr,
2078 					MSG_INTL(MSG_ERR_HSBADSYMNDX),
2079 				    file, elf_errmsg(0));
2080 				(void) fflush(stderr);
2081 				_str = MSG_INTL(MSG_STR_UNKNOWN);
2082 			} else {
2083 				_str = string(_cache, (GElf_Word)*hash,
2084 				    &cache[shdr->sh_link], file,
2085 				    _sym.st_name);
2086 			}
2087 
2088 			(void) snprintf(number, MAXNDXSIZE,
2089 			    /* LINTED */
2090 			    MSG_ORIG(MSG_FMT_INTEGER), (int)ndx);
2091 			(void) snprintf(_number, MAXNDXSIZE,
2092 			    MSG_ORIG(MSG_FMT_INDEX2), EC_XWORD(*hash));
2093 			dbg_print(MSG_ORIG(MSG_FMT_HASH_INFO), number, _number,
2094 			    demangle(_str, flags));
2095 
2096 			/*
2097 			 * Determine if this string is in the correct bucket.
2098 			 */
2099 			nhash = elf_hash(_str);
2100 			nbkt = nhash % bkts;
2101 			if (nbkt != ndx) {
2102 				(void) fprintf(stderr,
2103 				    MSG_INTL(MSG_ERR_BADHASH), file,
2104 				    /* LINTED */
2105 				    _cache->c_name, _str, (int)ndx, (int)nbkt);
2106 				(void) fflush(stderr);
2107 			}
2108 
2109 			/*
2110 			 * Determine if any other symbols are chained to this
2111 			 * bucket.
2112 			 */
2113 			_ndx = chain[*hash];
2114 			_cnt = 1;
2115 			while (_ndx) {
2116 				/* LINTED */
2117 				if (gelf_getsym(dsyms, (int)_ndx,
2118 				    &_sym) == NULL) {
2119 					(void) fprintf(stderr,
2120 						MSG_INTL(MSG_ERR_HSBADSYMNDX),
2121 					    file, elf_errmsg(0));
2122 					(void) fflush(stderr);
2123 					_str = MSG_INTL(MSG_STR_UNKNOWN);
2124 				} else
2125 					_str = string(_cache, _ndx,
2126 						&cache[shdr->sh_link], file,
2127 						_sym.st_name);
2128 
2129 				(void) snprintf(_number, MAXNDXSIZE,
2130 				    MSG_ORIG(MSG_FMT_INDEX2), EC_XWORD(_ndx));
2131 				dbg_print(MSG_ORIG(MSG_FMT_HASH_INFO),
2132 				    MSG_ORIG(MSG_STR_EMPTY), _number,
2133 				    demangle(_str, flags));
2134 				_ndx = chain[_ndx];
2135 				_cnt++;
2136 
2137 				/*
2138 				 * Determine if this string is in the correct
2139 				 * bucket.
2140 				 */
2141 				nhash = elf_hash(_str);
2142 				nbkt = nhash % bkts;
2143 				if (nbkt != ndx) {
2144 					(void) fprintf(stderr,
2145 					    MSG_INTL(MSG_ERR_BADHASH), file,
2146 					    _cache->c_name, _str,
2147 					    /* LINTED */
2148 					    (int)ndx, (int)nbkt);
2149 					(void) fflush(stderr);
2150 				}
2151 			}
2152 
2153 			if (_cnt >= MAXCOUNT) {
2154 				(void) fprintf(stderr,
2155 				    MSG_INTL(MSG_HASH_OVERFLW), file,
2156 				    _cache->c_name,
2157 				    /* LINTED */
2158 				    (int)ndx, _cnt);
2159 				(void) fflush(stderr);
2160 			} else
2161 				count[_cnt]++;
2162 		}
2163 		break;
2164 	}
2165 
2166 	/*
2167 	 * Print out the count information.
2168 	 */
2169 	bkts = cnt = 0;
2170 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
2171 	for (ndx = 0; ndx < MAXCOUNT; ndx++) {
2172 		GElf_Word	_cnt;
2173 
2174 		if ((_cnt = count[ndx]) == 0)
2175 			continue;
2176 
2177 		(void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
2178 		    /* LINTED */
2179 		    (int)_cnt);
2180 		/* LINTED */
2181 		dbg_print(MSG_INTL(MSG_ELF_HASH_BKTS1), number, (int)ndx);
2182 		bkts += _cnt;
2183 		/* LINTED */
2184 		cnt += (GElf_Word)(ndx * _cnt);
2185 	}
2186 	if (cnt) {
2187 		(void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
2188 		    /* LINTED */
2189 		    (int)bkts);
2190 		/* LINTED */
2191 		dbg_print(MSG_INTL(MSG_ELF_HASH_BKTS2), number, (int)cnt);
2192 	}
2193 }
2194 
2195 
2196 static void
2197 group(Cache *cache, GElf_Word shnum, const char *name, const char *file,
2198     uint32_t flags)
2199 {
2200 	GElf_Word	cnt;
2201 
2202 	for (cnt = 1; cnt < shnum; cnt++) {
2203 		Cache		*_cache = &cache[cnt];
2204 		GElf_Shdr	*shdr = &_cache->c_shdr;
2205 		Elf_Data	*dsyms;
2206 		GElf_Shdr	*symshdr;
2207 		GElf_Sym	sym;
2208 		const char	*symname;
2209 		char		flgstrbuf[MSG_GRP_COMDAT_SIZE + 10];
2210 		Word		*grpdata;
2211 		size_t		_cnt;
2212 		size_t		grpcnt;
2213 
2214 
2215 		if (shdr->sh_type != SHT_GROUP)
2216 			continue;
2217 		if (name && strcmp(name, _cache->c_name))
2218 			continue;
2219 		dbg_print(MSG_INTL(MSG_GRP_LINE1), _cache->c_name);
2220 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
2221 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2222 				file, _cache->c_name, EC_XWORD(shdr->sh_link));
2223 			(void) fflush(stderr);
2224 			continue;
2225 		}
2226 
2227 		if (shdr->sh_entsize != sizeof (Word)) {
2228 			(void) fprintf(stderr, MSG_INTL(MSG_GRP_BADENTSZ),
2229 				file, _cache->c_name,
2230 				EC_XWORD(shdr->sh_entsize));
2231 			(void) fflush(stderr);
2232 		}
2233 		symshdr = &(cache[shdr->sh_link].c_shdr);
2234 		if ((symshdr->sh_type != SHT_SYMTAB) &&
2235 		    (symshdr->sh_type != SHT_DYNSYM)) {
2236 			(void) fprintf(stderr, MSG_INTL(MSG_GRP_NOTSYMTAB),
2237 				file, _cache->c_name, EC_XWORD(shdr->sh_link));
2238 			(void) fflush(stderr);
2239 			continue;
2240 		}
2241 		dsyms = cache[shdr->sh_link].c_data;
2242 		if ((shdr->sh_info == SHN_UNDEF) || ((ulong_t)shdr->sh_info >
2243 		    (symshdr->sh_size / symshdr->sh_entsize))) {
2244 			(void) fprintf(stderr, MSG_INTL(MSG_GRP_BADSYMNDX),
2245 				file, _cache->c_name, EC_XWORD(shdr->sh_info));
2246 			(void) fflush(stderr);
2247 			continue;
2248 		}
2249 		flgstrbuf[0] = '[';
2250 		flgstrbuf[1] = '\0';
2251 		if ((shdr->sh_size != 0) &&
2252 		    (_cache->c_data) &&
2253 		    ((grpdata = (Word *)_cache->c_data->d_buf) != 0)) {
2254 			if (grpdata[0] & GRP_COMDAT) {
2255 				(void) strcat(flgstrbuf,
2256 					MSG_ORIG(MSG_GRP_COMDAT));
2257 			}
2258 			if ((grpdata[0] & ~GRP_COMDAT) != 0) {
2259 				(void) snprintf(flgstrbuf + strlen(flgstrbuf),
2260 				    (MSG_GRP_COMDAT_SIZE + 10),
2261 				    MSG_ORIG(MSG_GRP_FMT1),
2262 				    (uint_t)(grpdata[0] & ~GRP_COMDAT));
2263 			}
2264 		}
2265 		(void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_CLOSBRKT));
2266 
2267 		if (gelf_getsym(dsyms, shdr->sh_info, &sym) == NULL) {
2268 			(void) fprintf(stderr,
2269 				MSG_INTL(MSG_ERR_GRBADSYMNDX),
2270 				file, elf_errmsg(0));
2271 			(void) fflush(stderr);
2272 		}
2273 		symname = demangle(string(_cache, shdr->sh_link,
2274 			&cache[symshdr->sh_link], file, sym.st_name),
2275 			flags);
2276 		dbg_print(MSG_INTL(MSG_GRP_LINE2));
2277 		dbg_print(MSG_INTL(MSG_GRP_LINE3),
2278 			flgstrbuf, symname);
2279 		for (_cnt = 1, grpcnt = (shdr->sh_size / sizeof (Word));
2280 		    _cnt < grpcnt; _cnt++) {
2281 			char		index[MAXNDXSIZE];
2282 			const char	*sname;
2283 
2284 			(void) snprintf(index, MAXNDXSIZE,
2285 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(_cnt));
2286 			if (grpdata[_cnt] >= shnum) {
2287 				sname = MSG_INTL(MSG_GRP_INVALSCN);
2288 			} else {
2289 				sname = cache[grpdata[_cnt]].c_name;
2290 			}
2291 			(void) printf(MSG_ORIG(MSG_GRP_FMT2), index, sname,
2292 				(uint_t)grpdata[_cnt]);
2293 		}
2294 	}
2295 }
2296 
2297 
2298 static void
2299 got(Cache *cache, GElf_Word shnum, GElf_Word phnum, GElf_Ehdr *ehdr,
2300     const char *file)
2301 {
2302 	Cache		*gotcache = 0, *symtab = 0, *_cache;
2303 	GElf_Addr	gotbgn, gotend;
2304 	GElf_Shdr	*gotshdr;
2305 	GElf_Word	cnt, gotents, gotndx;
2306 	size_t		gentsize;
2307 	Got_info	*gottable;
2308 	char		*gotdata;
2309 	GElf_Sym	gsym;
2310 	GElf_Xword	gsymaddr;
2311 
2312 	/*
2313 	 * First, find the got.
2314 	 */
2315 	for (cnt = 1; cnt < shnum; cnt++) {
2316 		_cache = &cache[cnt];
2317 		if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT),
2318 		    MSG_ELF_GOT_SIZE) == 0) {
2319 			gotcache = _cache;
2320 			break;
2321 		}
2322 	}
2323 	if (!gotcache)
2324 		return;
2325 
2326 	/*
2327 	 * A got section within a relocatable object is suspicious.
2328 	 */
2329 	if (ehdr->e_type == ET_REL) {
2330 		(void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file,
2331 		    _cache->c_name);
2332 		(void) fflush(stderr);
2333 	}
2334 
2335 	gotshdr = &gotcache->c_shdr;
2336 	gotbgn = gotshdr->sh_addr;
2337 
2338 	if (gotshdr->sh_size == 0) {
2339 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2340 		    file, gotcache->c_name);
2341 		(void) fflush(stderr);
2342 		return;
2343 	}
2344 	gotend = gotbgn + gotshdr->sh_size;
2345 
2346 	/*
2347 	 * Some architectures don't properly set the sh_entsize
2348 	 * for the GOT table.  If it's not set we will default
2349 	 * to a size of a pointer.
2350 	 */
2351 	if ((gentsize = gotshdr->sh_entsize) == 0) {
2352 		if (ehdr->e_ident[EI_CLASS] == ELFCLASS64)
2353 			gentsize = sizeof (GElf_Xword);
2354 		else
2355 			gentsize = sizeof (GElf_Word);
2356 	}
2357 	/* LINTED */
2358 	gotents = (GElf_Word)(gotshdr->sh_size / gentsize);
2359 	gotdata = gotcache->c_data->d_buf;
2360 
2361 	if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) {
2362 		int err = errno;
2363 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
2364 			file, strerror(err));
2365 		(void) fflush(stderr);
2366 		return;
2367 	}
2368 
2369 	/*
2370 	 * Now we scan through all the sections looking for any relocations
2371 	 * that may be against the GOT.  Since these may not be isolated to a
2372 	 * .rel[a].got section we check them all.
2373 	 * While scanning sections save the symbol table entry (a symtab
2374 	 * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_.
2375 	 */
2376 	for (cnt = 1; cnt < shnum; cnt++) {
2377 		GElf_Shdr	*shdr;
2378 		GElf_Word	rtype;
2379 		Elf_Data	*dsyms, *reldata;
2380 		GElf_Rela	rela;
2381 		ulong_t		rcount;
2382 		int		ndx;
2383 		char		*sname;
2384 
2385 		_cache = &cache[cnt];
2386 		shdr = &_cache->c_shdr;
2387 
2388 		if ((symtab == 0) && (shdr->sh_type == SHT_DYNSYM)) {
2389 			symtab = _cache;
2390 			continue;
2391 		}
2392 		if (shdr->sh_type == SHT_SYMTAB) {
2393 			symtab = _cache;
2394 			continue;
2395 		}
2396 
2397 		rtype = shdr->sh_type;
2398 		if ((rtype != SHT_RELA) && (rtype != SHT_REL))
2399 			continue;
2400 
2401 		/*
2402 		 * Determine the relocation data and number.
2403 		 */
2404 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
2405 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2406 			    file, _cache->c_name);
2407 			(void) fflush(stderr);
2408 			continue;
2409 		}
2410 		rcount = shdr->sh_size / shdr->sh_entsize;
2411 
2412 		reldata = _cache->c_data;
2413 
2414 		/*
2415 		 * Get the data buffer for the associated symbol table.
2416 		 */
2417 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
2418 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2419 				file, _cache->c_name, EC_XWORD(shdr->sh_link));
2420 			(void) fflush(stderr);
2421 			continue;
2422 		}
2423 		dsyms = cache[shdr->sh_link].c_data;
2424 		if (dsyms->d_buf == 0) {
2425 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2426 			    file, cache[shdr->sh_link].c_name);
2427 			(void) fflush(stderr);
2428 			continue;
2429 		}
2430 
2431 		sname = cache[shdr->sh_link].c_name;
2432 		shdr = &cache[shdr->sh_link].c_shdr;
2433 		/*
2434 		 * Get the associated string table section.
2435 		 */
2436 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
2437 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2438 			    file, sname, EC_XWORD(shdr->sh_link));
2439 			(void) fflush(stderr);
2440 			continue;
2441 		}
2442 
2443 		/* LINTED */
2444 		for (ndx = 0; ndx < rcount; ++ndx) {
2445 			GElf_Sym 	_sym;
2446 			GElf_Word	sndx;
2447 			GElf_Addr	offset;
2448 			Got_info	*gip;
2449 			void		*relret;
2450 
2451 			if (rtype == SHT_RELA) {
2452 				relret = (void *)gelf_getrela(reldata, ndx,
2453 				    &rela);
2454 			} else {
2455 				relret = (void *)gelf_getrel(reldata, ndx,
2456 				    (GElf_Rel *)&rela);
2457 			}
2458 			if (relret == NULL) {
2459 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADREL),
2460 				    file, _cache->c_name, elf_errmsg(0));
2461 				(void) fflush(stderr);
2462 				break;
2463 			}
2464 
2465 			offset = rela.r_offset;
2466 			/* LINTED */
2467 			sndx = (GElf_Word)GELF_R_SYM(rela.r_info);
2468 
2469 			/*
2470 			 * Only pay attention to relocations against the GOT.
2471 			 */
2472 			if ((offset < gotbgn) || (offset > gotend))
2473 				continue;
2474 
2475 			/* LINTED */
2476 			gotndx = (GElf_Word)((offset - gotbgn) /
2477 			    gotshdr->sh_entsize);
2478 			gip = &gottable[gotndx];
2479 			if (gip->g_rshtype != 0) {
2480 				(void) fprintf(stderr,
2481 				    MSG_INTL(MSG_GOT_MULTIPLE), file,
2482 				    /* LINTED */
2483 				    EC_WORD(gotndx), EC_XWORD(offset));
2484 				(void) fflush(stderr);
2485 				continue;
2486 			}
2487 
2488 			/* LINTED */
2489 			if (gelf_getsym(dsyms, sndx, &_sym) == NULL) {
2490 				(void) fprintf(stderr,
2491 					MSG_INTL(MSG_ERR_RELBADSYMNDX),
2492 				    file, elf_errmsg(0));
2493 				(void) fflush(stderr);
2494 				gip->g_symname = MSG_INTL(MSG_STR_UNKNOWN);
2495 			} else {
2496 				gip->g_symname = string(_cache, sndx,
2497 				    &cache[shdr->sh_link], file, _sym.st_name);
2498 			}
2499 			gip->g_rshtype = rtype;
2500 			gip->g_rela = rela;
2501 		}
2502 	}
2503 
2504 	if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gsym, symtab, file))
2505 		gsymaddr = gsym.st_value;
2506 	else
2507 		gsymaddr = gotbgn;
2508 
2509 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
2510 	dbg_print(MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name, gotents);
2511 	Gelf_got_title(ehdr->e_ident[EI_CLASS]);
2512 
2513 	for (gotndx = 0; gotndx < gotents; gotndx++) {
2514 		Got_info	*gip;
2515 		Sword		gindex;
2516 		GElf_Addr	gaddr;
2517 		GElf_Xword	gotentry;
2518 
2519 		gip = &gottable[gotndx];
2520 
2521 		gaddr = gotbgn + (gotndx * gentsize);
2522 		/* LINTED */
2523 		gindex = (Sword)((gaddr - gsymaddr) / gentsize);
2524 
2525 		if (gentsize == sizeof (GElf_Word))
2526 			/* LINTED */
2527 			gotentry = (GElf_Xword)(*((GElf_Word *)(gotdata) +
2528 			    gotndx));
2529 		else
2530 			/* LINTED */
2531 			gotentry = *((GElf_Xword *)(gotdata) + gotndx);
2532 
2533 		Gelf_got_entry(ehdr, gindex, gaddr, gotentry, gip->g_rshtype,
2534 		    &gip->g_rela, gip->g_symname);
2535 	}
2536 
2537 	free(gottable);
2538 }
2539 
2540 void
2541 checksum(Elf *elf)
2542 {
2543 	dbg_print(MSG_ORIG(MSG_STR_EMPTY));
2544 	dbg_print(MSG_INTL(MSG_STR_CHECKSUM), gelf_checksum(elf));
2545 }
2546 
2547 static void
2548 regular(const char *file, Elf *elf, uint32_t flags, char *Nname, int wfd)
2549 {
2550 	Elf_Scn		*scn;
2551 	GElf_Ehdr	ehdr;
2552 	Elf_Data	*data;
2553 	uint_t		cnt;
2554 	GElf_Word	shnum, phnum;
2555 	size_t		shstrndx, _shnum, _phnum;
2556 	GElf_Shdr	nameshdr;
2557 	GElf_Shdr	shdr0;
2558 	GElf_Shdr	*_shdr0;
2559 	char		*names = 0;
2560 	Cache		*cache, *_cache;
2561 	Cache		*versymcache;
2562 
2563 	if (gelf_getehdr(elf, &ehdr) == NULL) {
2564 		failure(file, MSG_ORIG(MSG_ELF_GETEHDR));
2565 		return;
2566 	}
2567 
2568 	if (elf_getshnum(elf, &_shnum) == 0) {
2569 		failure(file, MSG_ORIG(MSG_ELF_GETSHNUM));
2570 		return;
2571 	}
2572 	/* LINTED */
2573 	shnum = (GElf_Word)_shnum;
2574 
2575 	if (elf_getshstrndx(elf, &shstrndx) == 0) {
2576 		failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX));
2577 		return;
2578 	}
2579 
2580 	if (elf_getphnum(elf, &_phnum) == 0) {
2581 		failure(file, MSG_ORIG(MSG_ELF_GETPHNUM));
2582 		return;
2583 	}
2584 	/* LINTED */
2585 	phnum = (GElf_Word)_phnum;
2586 
2587 	if ((scn = elf_getscn(elf, 0)) != NULL) {
2588 		if ((_shdr0 = gelf_getshdr(scn, &shdr0)) == NULL) {
2589 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
2590 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0);
2591 			(void) fflush(stderr);
2592 			return;
2593 		}
2594 	} else
2595 		_shdr0 = 0;
2596 
2597 	/*
2598 	 * Print the elf header.
2599 	 */
2600 	if (flags & FLG_EHDR)
2601 		Gelf_elf_header(&ehdr, _shdr0);
2602 
2603 	/*
2604 	 * Print the program headers.
2605 	 */
2606 	if ((flags & FLG_PHDR) && phnum != 0) {
2607 		GElf_Phdr phdr;
2608 
2609 		for (cnt = 0; cnt < phnum; cnt++) {
2610 			if (gelf_getphdr(elf, cnt, &phdr) == NULL) {
2611 				failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
2612 				return;
2613 			}
2614 
2615 			dbg_print(MSG_ORIG(MSG_STR_EMPTY));
2616 			dbg_print(MSG_INTL(MSG_ELF_PHDR), cnt);
2617 			Gelf_phdr_entry(ehdr.e_machine, &phdr);
2618 		}
2619 	}
2620 
2621 
2622 	/*
2623 	 * Return now if there are no section, if there's just one section to
2624 	 * act as an extension of the ELF header, or if on section information
2625 	 * was requested.
2626 	 */
2627 	if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) {
2628 		if ((ehdr.e_type == ET_CORE) && (flags & FLG_NOTE))
2629 			note(0, shnum, 0, file);
2630 		return;
2631 	}
2632 
2633 	/*
2634 	 * Obtain the .shstrtab data buffer to provide the required section
2635 	 * name strings.
2636 	 */
2637 	if ((scn = elf_getscn(elf, shstrndx)) == NULL) {
2638 		failure(file, MSG_ORIG(MSG_ELF_GETSCN));
2639 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR),
2640 		    EC_XWORD(shstrndx));
2641 		(void) fflush(stderr);
2642 	} else if ((data = elf_getdata(scn, NULL)) == NULL) {
2643 		failure(file, MSG_ORIG(MSG_ELF_GETDATA));
2644 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA),
2645 		    EC_XWORD(shstrndx));
2646 		(void) fflush(stderr);
2647 	} else if (gelf_getshdr(scn, &nameshdr) == NULL) {
2648 		failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
2649 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
2650 		    /* LINTED */
2651 		    (int)elf_ndxscn(scn));
2652 		(void) fflush(stderr);
2653 	} else if ((names = data->d_buf) == 0) {
2654 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file);
2655 		(void) fflush(stderr);
2656 	}
2657 
2658 	/*
2659 	 * Fill in the cache descriptor with information for each section.
2660 	 */
2661 	if ((cache = malloc(shnum * sizeof (Cache))) == 0) {
2662 		int err = errno;
2663 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
2664 		    file, strerror(err));
2665 		(void) fflush(stderr);
2666 		return;
2667 	}
2668 
2669 	*cache = _cache_init;
2670 	_cache = cache;
2671 	_cache++;
2672 
2673 	for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn);
2674 	    cnt++, _cache++) {
2675 		if (gelf_getshdr(scn, &_cache->c_shdr) == NULL) {
2676 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
2677 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
2678 			    /* LINTED */
2679 			    (int)elf_ndxscn(scn));
2680 			(void) fflush(stderr);
2681 		}
2682 
2683 		if (names && _cache->c_shdr.sh_name &&
2684 		    /* LINTED */
2685 		    (nameshdr.sh_size > _cache->c_shdr.sh_name))
2686 			_cache->c_name = names + _cache->c_shdr.sh_name;
2687 		else {
2688 			/*
2689 			 * If there exists no shstrtab data, or a section header
2690 			 * has no name (an invalid index of 0), then compose a
2691 			 * name for each section.
2692 			 */
2693 			char	scnndxnm[100];
2694 
2695 			(void) snprintf(scnndxnm, 100, MSG_INTL(MSG_FMT_SCNNDX),
2696 			    cnt);
2697 
2698 			/*
2699 			 * Although we have a valid shstrtab section inform the
2700 			 * user if this section name index exceeds the shstrtab
2701 			 * data.
2702 			 */
2703 			if (names &&
2704 			    /* LINTED */
2705 			    (nameshdr.sh_size <= _cache->c_shdr.sh_name)) {
2706 				(void) fprintf(stderr,
2707 				    MSG_INTL(MSG_ERR_BADSHNAME), file,
2708 				    _cache->c_name,
2709 				    EC_XWORD(_cache->c_shdr.sh_name));
2710 				(void) fflush(stderr);
2711 			}
2712 
2713 			if ((_cache->c_name =
2714 			    malloc(strlen(scnndxnm) + 1)) == 0) {
2715 				int err = errno;
2716 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
2717 				    file, strerror(err));
2718 				(void) fflush(stderr);
2719 				return;
2720 			}
2721 			(void) strcpy(_cache->c_name, scnndxnm);
2722 		}
2723 
2724 		if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) {
2725 			failure(file, MSG_ORIG(MSG_ELF_GETDATA));
2726 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA),
2727 			    /* LINTED */
2728 			    (int)elf_ndxscn(scn));
2729 			(void) fflush(stderr);
2730 		}
2731 
2732 		/*
2733 		 * Do we wish to write the section out?
2734 		 */
2735 		if (wfd && Nname && (strcmp(Nname, _cache->c_name) == 0)) {
2736 			(void) write(wfd, _cache->c_data->d_buf,
2737 			    _cache->c_data->d_size);
2738 		}
2739 	}
2740 
2741 	if (flags & FLG_SHDR)
2742 		sections(file, cache, shnum, phnum, &ehdr, Nname);
2743 
2744 	if (flags & FLG_INTERP)
2745 		interp(file, cache, shnum, phnum, &ehdr, elf);
2746 
2747 	versymcache = versions(cache, shnum, file, flags);
2748 
2749 	if (flags & FLG_SYMBOLS)
2750 		symbols(cache, shnum, phnum, &ehdr, Nname, versymcache, file);
2751 
2752 	if (flags & FLG_HASH)
2753 		hash(cache, shnum, Nname, file, flags);
2754 
2755 	if (flags & FLG_GOT)
2756 		got(cache, shnum, phnum, &ehdr, file);
2757 
2758 	if (flags & FLG_GROUP)
2759 		group(cache, shnum, Nname, file, flags);
2760 
2761 	if (flags & FLG_SYMINFO)
2762 		syminfo(cache, shnum, file);
2763 
2764 	if (flags & FLG_RELOC)
2765 		reloc(cache, shnum, phnum, &ehdr, Nname, file, flags);
2766 
2767 	if (flags & FLG_DYNAMIC)
2768 		dynamic(cache, shnum, &ehdr, file);
2769 
2770 	if (flags & FLG_NOTE)
2771 		note(cache, shnum, Nname, file);
2772 
2773 	if (flags & FLG_MOVE)
2774 		move(cache, shnum, Nname, file, flags);
2775 
2776 	if (flags & FLG_CHECKSUM)
2777 		checksum(elf);
2778 
2779 	if (flags & FLG_CAP)
2780 		cap(file, cache, shnum, phnum, &ehdr, elf);
2781 
2782 	if (flags & FLG_UNWIND)
2783 		unwind(cache, shnum, phnum, &ehdr, Nname, file, elf);
2784 
2785 	free(cache);
2786 }
2787 
2788 static void
2789 archive(const char *file, int fd, Elf *elf, uint32_t flags, char *Nname,
2790     int wfd)
2791 {
2792 	Elf_Cmd		cmd = ELF_C_READ;
2793 	Elf_Arhdr	*arhdr;
2794 	Elf		*_elf = 0;
2795 	size_t		ptr;
2796 	Elf_Arsym	*arsym = 0;
2797 
2798 	/*
2799 	 * Determine if the archive sysmbol table itself is required.
2800 	 */
2801 	if ((flags & FLG_SYMBOLS) && ((Nname == NULL) ||
2802 	    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))) {
2803 		/*
2804 		 * Get the archive symbol table.
2805 		 */
2806 		if (((arsym = elf_getarsym(elf, &ptr)) == 0) && elf_errno()) {
2807 			/*
2808 			 * The arsym could be 0 even though there was no error.
2809 			 * Print the error message only when there was
2810 			 * real error from elf_getarsym().
2811 			 */
2812 			failure(file, MSG_ORIG(MSG_ELF_GETARSYM));
2813 			return;
2814 		}
2815 	}
2816 
2817 	/*
2818 	 * Print the archive symbol table only when the archive symbol
2819 	 * table exists and it was requested to print.
2820 	 */
2821 	if (arsym) {
2822 		size_t		cnt;
2823 		char		index[MAXNDXSIZE];
2824 		size_t		offset = 0, _offset = 0;
2825 
2826 		/*
2827 		 * Print out all the symbol entries.
2828 		 */
2829 		dbg_print(MSG_INTL(MSG_ARCHIVE_SYMTAB));
2830 		dbg_print(MSG_INTL(MSG_ARCHIVE_FIELDS));
2831 
2832 		for (cnt = 0; cnt < ptr; cnt++, arsym++) {
2833 			/*
2834 			 * For each object obtain an elf descriptor so that we
2835 			 * can establish the members name.  Note, we have had
2836 			 * archives where the archive header has not been
2837 			 * obtainable so be lenient with errors.
2838 			 */
2839 			if ((offset == 0) || ((arsym->as_off != 0) &&
2840 			    (arsym->as_off != _offset))) {
2841 
2842 				if (_elf)
2843 					(void) elf_end(_elf);
2844 
2845 				if (elf_rand(elf, arsym->as_off) !=
2846 				    arsym->as_off) {
2847 					failure(file, MSG_ORIG(MSG_ELF_RAND));
2848 					arhdr = 0;
2849 				} else if ((_elf = elf_begin(fd,
2850 				    ELF_C_READ, elf)) == 0) {
2851 					failure(file, MSG_ORIG(MSG_ELF_BEGIN));
2852 					arhdr = 0;
2853 				} else if ((arhdr = elf_getarhdr(_elf)) == 0) {
2854 					failure(file,
2855 					    MSG_ORIG(MSG_ELF_GETARHDR));
2856 					arhdr = 0;
2857 				}
2858 
2859 				_offset = arsym->as_off;
2860 				if (offset == 0)
2861 					offset = _offset;
2862 			}
2863 
2864 			(void) snprintf(index, MAXNDXSIZE,
2865 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(cnt));
2866 			if (arsym->as_off)
2867 				dbg_print(MSG_ORIG(MSG_FMT_ARSYM1), index,
2868 				    /* LINTED */
2869 				    (int)arsym->as_off, arhdr ? arhdr->ar_name :
2870 				    MSG_INTL(MSG_STR_UNKNOWN), (arsym->as_name ?
2871 				    demangle(arsym->as_name, flags) :
2872 				    MSG_INTL(MSG_STR_NULL)));
2873 			else
2874 				dbg_print(MSG_ORIG(MSG_FMT_ARSYM2), index,
2875 				    /* LINTED */
2876 				    (int)arsym->as_off);
2877 		}
2878 
2879 		if (_elf)
2880 			(void) elf_end(_elf);
2881 
2882 		/*
2883 		 * If we only need the archive symbol table return.
2884 		 */
2885 		if ((flags & FLG_SYMBOLS) && Nname &&
2886 		    (strcmp(Nname, MSG_ORIG(MSG_ELF_ARSYM)) == 0))
2887 			return;
2888 
2889 		/*
2890 		 * Reset elf descriptor in preparation for processing each
2891 		 * member.
2892 		 */
2893 		if (offset)
2894 			(void) elf_rand(elf, offset);
2895 	}
2896 
2897 	/*
2898 	 * Process each object within the archive.
2899 	 */
2900 	while ((_elf = elf_begin(fd, cmd, elf)) != NULL) {
2901 		char	name[MAXPATHLEN];
2902 
2903 		if ((arhdr = elf_getarhdr(_elf)) == NULL) {
2904 			failure(file, MSG_ORIG(MSG_ELF_GETARHDR));
2905 			return;
2906 		}
2907 		if (*arhdr->ar_name != '/') {
2908 			(void) snprintf(name, MAXPATHLEN,
2909 			    MSG_ORIG(MSG_FMT_ARNAME), file, arhdr->ar_name);
2910 			dbg_print(MSG_ORIG(MSG_FMT_NLSTR), name);
2911 
2912 			switch (elf_kind(_elf)) {
2913 			case ELF_K_AR:
2914 				archive(name, fd, _elf, flags, Nname, wfd);
2915 				break;
2916 			case ELF_K_ELF:
2917 				regular(name, _elf, flags, Nname, wfd);
2918 				break;
2919 			default:
2920 				(void) fprintf(stderr,
2921 					MSG_INTL(MSG_ERR_BADFILE), name);
2922 				(void) fflush(stderr);
2923 				break;
2924 			}
2925 		}
2926 
2927 		cmd = elf_next(_elf);
2928 		(void) elf_end(_elf);
2929 	}
2930 }
2931 
2932 int
2933 main(int argc, char **argv, char **envp)
2934 {
2935 	Elf		*elf;
2936 	int		var, fd, wfd = 0;
2937 	char		*Nname = NULL, *wname = 0;
2938 	uint32_t	flags = 0, dbg_flags = 0;
2939 
2940 	/*
2941 	 * If we're on a 64-bit kernel, try to exec a full 64-bit version of
2942 	 * the binary.  If successful, conv_check_native() won't return.
2943 	 */
2944 	conv_check_native(argv, envp);
2945 
2946 	/*
2947 	 * Establish locale.
2948 	 */
2949 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
2950 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
2951 
2952 	(void) setvbuf(stdout, NULL, _IOLBF, 0);
2953 	(void) setvbuf(stderr, NULL, _IOLBF, 0);
2954 
2955 	opterr = 0;
2956 	while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) {
2957 		switch (var) {
2958 		case 'C':
2959 			flags |= FLG_DEMANGLE;
2960 			break;
2961 		case 'c':
2962 			flags |= FLG_SHDR;
2963 			break;
2964 		case 'd':
2965 			flags |= FLG_DYNAMIC;
2966 			break;
2967 		case 'e':
2968 			flags |= FLG_EHDR;
2969 			break;
2970 		case 'G':
2971 			flags |= FLG_GOT;
2972 			break;
2973 		case 'g':
2974 			flags |= FLG_GROUP;
2975 			break;
2976 		case 'H':
2977 			flags |= FLG_CAP;
2978 			break;
2979 		case 'h':
2980 			flags |= FLG_HASH;
2981 			break;
2982 		case 'i':
2983 			flags |= FLG_INTERP;
2984 			break;
2985 		case 'k':
2986 			flags |= FLG_CHECKSUM;
2987 			break;
2988 		case 'l':
2989 			flags |= FLG_LONGNAME;
2990 			break;
2991 		case 'm':
2992 			flags |= FLG_MOVE;
2993 			break;
2994 		case 'N':
2995 			Nname = optarg;
2996 			break;
2997 		case 'n':
2998 			flags |= FLG_NOTE;
2999 			break;
3000 		case 'p':
3001 			flags |= FLG_PHDR;
3002 			break;
3003 		case 'r':
3004 			flags |= FLG_RELOC;
3005 			break;
3006 		case 's':
3007 			flags |= FLG_SYMBOLS;
3008 			break;
3009 		case 'u':
3010 			flags |= FLG_UNWIND;
3011 			break;
3012 		case 'v':
3013 			flags |= FLG_VERSIONS;
3014 			break;
3015 		case 'w':
3016 			wname = optarg;
3017 			break;
3018 		case 'y':
3019 			flags |= FLG_SYMINFO;
3020 			break;
3021 		case '?':
3022 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
3023 			    basename(argv[0]));
3024 			detail_usage();
3025 			return (1);
3026 		default:
3027 			break;
3028 		}
3029 	}
3030 
3031 	/*
3032 	 * Validate any arguments.
3033 	 */
3034 	if (flags == 0) {
3035 		if (!wname && !Nname) {
3036 			flags = FLG_EVERYTHING;
3037 		} else if (!wname || !Nname) {
3038 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
3039 			    basename(argv[0]));
3040 			return (1);
3041 		}
3042 	}
3043 
3044 	if ((var = argc - optind) == 0) {
3045 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
3046 		    basename(argv[0]));
3047 		return (1);
3048 	}
3049 
3050 	/*
3051 	 * If the -C option is used by itself, report an error since the option
3052 	 * has no use without other symbol name generating options.
3053 	 *
3054 	 * If the -l option is used by itself, report an error.
3055 	 */
3056 	if ((flags == FLG_DEMANGLE) || (flags == FLG_LONGNAME) ||
3057 	    (flags == (FLG_DEMANGLE | FLG_LONGNAME))) {
3058 		if (flags & FLG_DEMANGLE)
3059 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DEMANGLE));
3060 		if (flags & FLG_LONGNAME)
3061 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_LONGNAME));
3062 		return (1);
3063 	}
3064 
3065 	/*
3066 	 * If the -l/-C option is specified, set up the liblddbg.so.
3067 	 */
3068 	if (flags & FLG_LONGNAME)
3069 		dbg_flags = DBG_LONG;
3070 	if (flags & FLG_DEMANGLE)
3071 		dbg_flags |= DBG_DEMANGLE;
3072 	if (dbg_flags)
3073 		Dbg_set(dbg_flags);
3074 
3075 	/*
3076 	 * If the -w option has indicated an output file open it.  It's
3077 	 * arguable whether this option has much use when multiple files are
3078 	 * being processed.
3079 	 */
3080 	if (wname) {
3081 		if ((wfd = open(wname, (O_RDWR | O_CREAT | O_TRUNC),
3082 		    0666)) < 0) {
3083 			int err = errno;
3084 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
3085 			    wname, strerror(err));
3086 			(void) fflush(stderr);
3087 			wfd = 0;
3088 		}
3089 	}
3090 
3091 	/*
3092 	 * Open the input file and initialize the elf interface.
3093 	 */
3094 	for (; optind < argc; optind++) {
3095 		const char	*file = argv[optind];
3096 
3097 		if ((fd = open(argv[optind], O_RDONLY)) == -1) {
3098 			int err = errno;
3099 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_OPEN),
3100 			    file, strerror(err));
3101 			(void) fflush(stderr);
3102 			continue;
3103 		}
3104 		(void) elf_version(EV_CURRENT);
3105 		if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
3106 			failure(file, MSG_ORIG(MSG_ELF_BEGIN));
3107 			(void) close(fd);
3108 			continue;
3109 		}
3110 
3111 		if (var > 1)
3112 			dbg_print(MSG_ORIG(MSG_FMT_NLSTRNL), file);
3113 
3114 		switch (elf_kind(elf)) {
3115 		case ELF_K_AR:
3116 			archive(file, fd, elf, flags, Nname, wfd);
3117 			break;
3118 		case ELF_K_ELF:
3119 			regular(file, elf, flags, Nname, wfd);
3120 			break;
3121 		default:
3122 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADFILE), file);
3123 			(void) fflush(stderr);
3124 			break;
3125 		}
3126 
3127 		(void) close(fd);
3128 		(void) elf_end(elf);
3129 	}
3130 
3131 	if (wfd)
3132 		(void) close(wfd);
3133 	return (0);
3134 }
3135