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