xref: /illumos-gate/usr/src/cmd/sgs/elfdump/common/elfdump.c (revision 34a0f871d192b33b865455a8812a3d34c1866315)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Dump an elf file.
30  */
31 #include	<machdep.h>
32 #include	<sys/elf_386.h>
33 #include	<sys/elf_amd64.h>
34 #include	<sys/elf_SPARC.h>
35 #include	<dwarf.h>
36 #include	<unistd.h>
37 #include	<errno.h>
38 #include	<strings.h>
39 #include	<debug.h>
40 #include	<conv.h>
41 #include	<msg.h>
42 #include	<_elfdump.h>
43 
44 
45 
46 /*
47  * VERSYM_STATE is used to maintain information about the VERSYM section
48  * in the object being analyzed. It is filled in by versions(), and used
49  * by init_symtbl_state() when displaying symbol information.
50  *
51  * Note that the value of the gnu field is a hueristic guess,
52  * based on the section names.
53  */
54 typedef struct {
55 	Cache	*cache;		/* Pointer to cache entry for VERSYM */
56 	Versym	*data;		/* Pointer to versym array */
57 	int	num_verdef;	/* # of versions defined in object */
58 	int	gnu;		/* True if we think obj produced by GNU tools */
59 } VERSYM_STATE;
60 
61 /*
62  * SYMTBL_STATE is used to maintain information about a single symbol
63  * table section, for use by the routines that display symbol information.
64  */
65 typedef struct {
66 	const char	*file;		/* Name of file */
67 	Ehdr		*ehdr;		/* ELF header for file */
68 	Cache		*cache;		/* Cache of all section headers */
69 	Word		shnum;		/* # of sections in cache */
70 	Cache		*seccache;	/* Cache of symbol table section hdr */
71 	Word		secndx;		/* Index of symbol table section hdr */
72 	const char	*secname;	/* Name of section */
73 	uint_t		flags;		/* Command line option flags */
74 	struct {			/* Extended section index data */
75 		int	checked;	/* TRUE if already checked for shxndx */
76 		Word	*data;		/* NULL, or extended section index */
77 					/*	used for symbol table entries */
78 		uint_t	n;		/* # items in shxndx.data */
79 	} shxndx;
80 	VERSYM_STATE	*versym;	/* NULL, or associated VERSYM section */
81 	Sym 		*sym;		/* Array of symbols */
82 	Word		symn;		/* # of symbols */
83 } SYMTBL_STATE;
84 
85 
86 
87 /*
88  * Focal point for verifying symbol names.
89  */
90 static const char *
91 string(Cache *refsec, Word ndx, Cache *strsec, const char *file, Word name)
92 {
93 	static Cache	*osec = 0;
94 	static int	nostr;
95 	const char	*strs;
96 	Word		strn;
97 
98 	if (strsec->c_data == NULL)
99 		return (NULL);
100 
101 	strs = (char *)strsec->c_data->d_buf;
102 	strn = strsec->c_data->d_size;
103 
104 	/*
105 	 * Only print a diagnostic regarding an empty string table once per
106 	 * input section being processed.
107 	 */
108 	if (osec != refsec) {
109 		osec = refsec;
110 		nostr = 0;
111 	}
112 
113 	/*
114 	 * Is the string table offset within range of the available strings?
115 	 */
116 	if (name >= strn) {
117 		/*
118 		 * Do we have a empty string table?
119 		 */
120 		if (strs == 0) {
121 			if (nostr == 0) {
122 				(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
123 				    file, strsec->c_name);
124 				nostr++;
125 			}
126 		} else {
127 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSTOFF),
128 			    file, refsec->c_name, EC_WORD(ndx), strsec->c_name,
129 			    EC_WORD(name), EC_WORD(strn - 1));
130 		}
131 
132 		/*
133 		 * Return the empty string so that the calling function can
134 		 * continue it's output diagnostics.
135 		 */
136 		return (MSG_INTL(MSG_STR_UNKNOWN));
137 	}
138 	return (strs + name);
139 }
140 
141 /*
142  * Relocations can reference section symbols and standard symbols.  If the
143  * former, establish the section name.
144  */
145 static const char *
146 relsymname(Cache *cache, Cache *csec, Cache *strsec, Word symndx, Word symnum,
147     Word relndx, Sym *syms, char *secstr, size_t secsz, const char *file,
148     uint_t flags)
149 {
150 	Sym	*sym;
151 
152 	if (symndx >= symnum) {
153 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_RELBADSYMNDX),
154 		    file, EC_WORD(symndx), EC_WORD(relndx));
155 		return (MSG_INTL(MSG_STR_UNKNOWN));
156 	}
157 
158 	sym = (Sym *)(syms + symndx);
159 
160 	/*
161 	 * If the symbol represents a section offset construct an appropriate
162 	 * string.
163 	 */
164 	if ((ELF_ST_TYPE(sym->st_info) == STT_SECTION) && (sym->st_name == 0)) {
165 		if (flags & FLG_LONGNAME)
166 			(void) snprintf(secstr, secsz,
167 			    MSG_INTL(MSG_STR_L_SECTION),
168 			    cache[sym->st_shndx].c_name);
169 		else
170 			(void) snprintf(secstr, secsz,
171 			    MSG_INTL(MSG_STR_SECTION),
172 			    cache[sym->st_shndx].c_name);
173 		return ((const char *)secstr);
174 	}
175 
176 	return (string(csec, symndx, strsec, file, sym->st_name));
177 }
178 
179 /*
180  * Focal point for establishing a string table section.  Data such as the
181  * dynamic information simply points to a string table.  Data such as
182  * relocations, reference a symbol table, which in turn is associated with a
183  * string table.
184  */
185 static int
186 stringtbl(Cache *cache, int symtab, Word ndx, Word shnum, const char *file,
187     Word *symnum, Cache **symsec, Cache **strsec)
188 {
189 	Shdr	*shdr = cache[ndx].c_shdr;
190 
191 	if (symtab) {
192 		/*
193 		 * Validate the symbol table section.
194 		 */
195 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
196 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
197 			    file, cache[ndx].c_name, EC_WORD(shdr->sh_link));
198 			return (0);
199 		}
200 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
201 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
202 			    file, cache[ndx].c_name);
203 			return (0);
204 		}
205 
206 		/*
207 		 * Obtain, and verify the symbol table data.
208 		 */
209 		if ((cache[ndx].c_data == NULL) ||
210 		    (cache[ndx].c_data->d_buf == NULL)) {
211 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
212 			    file, cache[ndx].c_name);
213 			return (0);
214 		}
215 
216 		/*
217 		 * Establish the string table index.
218 		 */
219 		ndx = shdr->sh_link;
220 		shdr = cache[ndx].c_shdr;
221 
222 		/*
223 		 * Return symbol table information.
224 		 */
225 		if (symnum)
226 			*symnum = (shdr->sh_size / shdr->sh_entsize);
227 		if (symsec)
228 			*symsec = &cache[ndx];
229 	}
230 
231 	/*
232 	 * Validate the associated string table section.
233 	 */
234 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
235 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
236 		    file, cache[ndx].c_name, EC_WORD(shdr->sh_link));
237 		return (0);
238 	}
239 
240 	if (strsec)
241 		*strsec = &cache[shdr->sh_link];
242 
243 	return (1);
244 }
245 
246 /*
247  * Lookup a symbol and set Sym accordingly.
248  */
249 static int
250 symlookup(const char *name, Cache *cache, Word shnum, Sym **sym,
251     Cache *symtab, const char *file)
252 {
253 	Shdr	*shdr;
254 	Word	symn, cnt;
255 	Sym	*syms;
256 
257 	if (symtab == 0)
258 		return (0);
259 
260 	shdr = symtab->c_shdr;
261 
262 	/*
263 	 * Determine the symbol data and number.
264 	 */
265 	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
266 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
267 		    file, symtab->c_name);
268 		return (0);
269 	}
270 	if (symtab->c_data == NULL)
271 		return (0);
272 
273 	/* LINTED */
274 	symn = (Word)(shdr->sh_size / shdr->sh_entsize);
275 	syms = (Sym *)symtab->c_data->d_buf;
276 
277 	/*
278 	 * Get the associated string table section.
279 	 */
280 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
281 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
282 		    file, symtab->c_name, EC_WORD(shdr->sh_link));
283 		return (0);
284 	}
285 
286 	/*
287 	 * Loop through the symbol table to find a match.
288 	 */
289 	for (cnt = 0; cnt < symn; syms++, cnt++) {
290 		const char	*symname;
291 
292 		symname = string(symtab, cnt, &cache[shdr->sh_link], file,
293 		    syms->st_name);
294 
295 		if (symname && (strcmp(name, symname) == 0)) {
296 			*sym = syms;
297 			return (1);
298 		}
299 	}
300 	return (0);
301 }
302 
303 /*
304  * Print section headers.
305  */
306 static void
307 sections(const char *file, Cache *cache, Word shnum, Ehdr *ehdr,
308     const char *name)
309 {
310 	size_t	seccnt;
311 
312 	for (seccnt = 1; seccnt < shnum; seccnt++) {
313 		Cache		*_cache = &cache[seccnt];
314 		Shdr		*shdr = _cache->c_shdr;
315 		const char	*secname = _cache->c_name;
316 
317 		/*
318 		 * Although numerous section header entries can be zero, it's
319 		 * usually a sign of trouble if the type is zero.
320 		 */
321 		if (shdr->sh_type == 0) {
322 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHTYPE),
323 			    file, secname, EC_WORD(shdr->sh_type));
324 		}
325 
326 		if (name && strcmp(name, secname))
327 			continue;
328 
329 		/*
330 		 * Identify any sections that are suspicious.  A .got section
331 		 * shouldn't exist in a relocatable object.
332 		 */
333 		if (ehdr->e_type == ET_REL) {
334 			if (strncmp(secname, MSG_ORIG(MSG_ELF_GOT),
335 			    MSG_ELF_GOT_SIZE) == 0) {
336 				(void) fprintf(stderr,
337 				    MSG_INTL(MSG_GOT_UNEXPECTED), file,
338 				    secname);
339 			}
340 		}
341 
342 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
343 		dbg_print(0, MSG_INTL(MSG_ELF_SHDR), EC_WORD(seccnt), secname);
344 		Elf_shdr(0, ehdr->e_machine, shdr);
345 	}
346 }
347 
348 /*
349  * A couple of instances of unwind data are printed as tables of 8 data items
350  * expressed as 0x?? integers.
351  */
352 #define	UNWINDTBLSZ	10 + (8 * 5) + 1
353 
354 static void
355 unwindtbl(uint64_t *ndx, uint_t len, uchar_t *data, uint64_t doff,
356     const char *msg, const char *pre, size_t plen)
357 {
358 	char	buffer[UNWINDTBLSZ];
359 	uint_t	boff = plen, cnt = 0;
360 
361 	dbg_print(0, msg);
362 	(void) strncpy(buffer, pre, UNWINDTBLSZ);
363 
364 	while (*ndx < (len + 4)) {
365 		if (cnt == 8) {
366 			dbg_print(0, buffer);
367 			boff = plen;
368 			cnt = 0;
369 		}
370 		(void) snprintf(&buffer[boff], UNWINDTBLSZ - boff,
371 		    MSG_ORIG(MSG_UNW_TBLENTRY), data[doff + (*ndx)++]);
372 		boff += 5;
373 		cnt++;
374 	}
375 	if (cnt)
376 		dbg_print(0, buffer);
377 }
378 
379 /*
380  * Obtain a specified Phdr entry.
381  */
382 static Phdr *
383 getphdr(Word phnum, Word type, const char *file, Elf *elf)
384 {
385 	Word	cnt;
386 	Phdr	*phdr;
387 
388 	if ((phdr = elf_getphdr(elf)) == NULL) {
389 		failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
390 		return (0);
391 	}
392 
393 	for (cnt = 0; cnt < phnum; phdr++, cnt++) {
394 		if (phdr->p_type == type)
395 			return (phdr);
396 	}
397 	return (0);
398 }
399 
400 static void
401 unwind(Cache *cache, Word shnum, Word phnum, Ehdr *ehdr, const char *name,
402     const char *file, Elf *elf)
403 {
404 	Word	cnt;
405 	Phdr	*uphdr = 0;
406 
407 	/*
408 	 * For the moment - UNWIND is only relevant for a AMD64 object.
409 	 */
410 	if (ehdr->e_machine != EM_AMD64)
411 		return;
412 
413 	if (phnum)
414 		uphdr = getphdr(phnum, PT_SUNW_UNWIND, file, elf);
415 
416 	for (cnt = 1; cnt < shnum; cnt++) {
417 		Cache		*_cache = &cache[cnt];
418 		Shdr		*shdr = _cache->c_shdr;
419 		uchar_t		*data;
420 		size_t		datasize;
421 		uint64_t	off, ndx, frame_ptr, fde_cnt, tabndx;
422 		uint_t		vers, frame_ptr_enc, fde_cnt_enc, table_enc;
423 
424 		/*
425 		 * AMD64 - this is a strmcp() just to find the gcc produced
426 		 * sections.  Soon gcc should be setting the section type - and
427 		 * we'll not need this strcmp().
428 		 */
429 		if ((shdr->sh_type != SHT_AMD64_UNWIND) &&
430 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRM),
431 		    MSG_SCN_FRM_SIZE) != 0) &&
432 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
433 		    MSG_SCN_FRMHDR_SIZE) != 0))
434 			continue;
435 		if (name && strcmp(name, _cache->c_name))
436 			continue;
437 
438 		if (_cache->c_data == NULL)
439 			continue;
440 
441 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
442 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_UNWIND), _cache->c_name);
443 
444 		data = (uchar_t *)(_cache->c_data->d_buf);
445 		datasize = _cache->c_data->d_size;
446 		off = 0;
447 
448 		/*
449 		 * Is this a .eh_frame_hdr
450 		 */
451 		if ((uphdr && (shdr->sh_addr == uphdr->p_vaddr)) ||
452 		    (strncmp(_cache->c_name, MSG_ORIG(MSG_SCN_FRMHDR),
453 		    MSG_SCN_FRMHDR_SIZE) == 0)) {
454 
455 			dbg_print(0, MSG_ORIG(MSG_UNW_FRMHDR));
456 			ndx = 0;
457 
458 			vers = data[ndx++];
459 			frame_ptr_enc = data[ndx++];
460 			fde_cnt_enc = data[ndx++];
461 			table_enc = data[ndx++];
462 
463 			dbg_print(0, MSG_ORIG(MSG_UNW_FRMVERS), vers);
464 
465 			frame_ptr = dwarf_ehe_extract(data, &ndx, frame_ptr_enc,
466 			    ehdr->e_ident, shdr->sh_addr + ndx);
467 
468 			dbg_print(0, MSG_ORIG(MSG_UNW_FRPTRENC),
469 			    conv_dwarf_ehe(frame_ptr_enc), EC_XWORD(frame_ptr));
470 
471 			fde_cnt = dwarf_ehe_extract(data, &ndx, fde_cnt_enc,
472 			    ehdr->e_ident, shdr->sh_addr + ndx);
473 
474 			dbg_print(0, MSG_ORIG(MSG_UNW_FDCNENC),
475 			    conv_dwarf_ehe(fde_cnt_enc), EC_XWORD(fde_cnt));
476 			dbg_print(0, MSG_ORIG(MSG_UNW_TABENC),
477 			    conv_dwarf_ehe(table_enc));
478 			dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB1));
479 			dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTAB2));
480 
481 			for (tabndx = 0; tabndx < fde_cnt; tabndx++) {
482 				dbg_print(0, MSG_ORIG(MSG_UNW_BINSRTABENT),
483 				    EC_XWORD(dwarf_ehe_extract(data, &ndx,
484 				    table_enc, ehdr->e_ident, shdr->sh_addr)),
485 				    EC_XWORD(dwarf_ehe_extract(data, &ndx,
486 				    table_enc, ehdr->e_ident, shdr->sh_addr)));
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, ciePflag, cieZflag;
498 			uint_t		cieaugndx, length, id;
499 			uint64_t	ciecalign, ciedalign;
500 			char		*cieaugstr;
501 
502 			ndx = 0;
503 			/*
504 			 * extract length in lsb format
505 			 */
506 			length = LSB32EXTRACT(data + off + ndx);
507 			ndx += 4;
508 
509 			/*
510 			 * extract CIE id in lsb format
511 			 */
512 			id = LSB32EXTRACT(data + off + ndx);
513 			ndx += 4;
514 
515 			/*
516 			 * A CIE record has a id of '0', otherwise this is a
517 			 * FDE entry and the 'id' is the CIE pointer.
518 			 */
519 			if (id == 0) {
520 				uint64_t    persVal;
521 
522 				cielength = length;
523 				cieid = id;
524 				cieLflag = ciePflag = cieRflag = cieZflag = 0;
525 
526 				dbg_print(0, MSG_ORIG(MSG_UNW_CIE),
527 				    EC_XWORD(shdr->sh_addr + off));
528 				dbg_print(0, MSG_ORIG(MSG_UNW_CIELNGTH),
529 				    cielength, cieid);
530 
531 				cieversion = data[off + ndx];
532 				ndx += 1;
533 				cieaugstr = (char *)(&data[off + ndx]);
534 				ndx += strlen(cieaugstr) + 1;
535 
536 				dbg_print(0, MSG_ORIG(MSG_UNW_CIEVERS),
537 				    cieversion, cieaugstr);
538 
539 				ciecalign = uleb_extract(&data[off], &ndx);
540 				ciedalign = sleb_extract(&data[off], &ndx);
541 				cieretaddr = data[off + ndx];
542 				ndx += 1;
543 
544 				dbg_print(0, MSG_ORIG(MSG_UNW_CIECALGN),
545 				    EC_XWORD(ciecalign), EC_XWORD(ciedalign),
546 				    cieretaddr);
547 
548 				if (cieaugstr[0])
549 				    dbg_print(0, MSG_ORIG(MSG_UNW_CIEAUXVAL));
550 
551 				for (cieaugndx = 0; cieaugstr[cieaugndx];
552 				    cieaugndx++) {
553 					uint_t	val;
554 
555 					switch (cieaugstr[cieaugndx]) {
556 					case 'z':
557 					    val = uleb_extract(&data[off],
558 						&ndx);
559 					    dbg_print(0,
560 						MSG_ORIG(MSG_UNW_CIEAUXSIZE),
561 						val);
562 					    cieZflag = 1;
563 					    break;
564 					case 'P':
565 					    ciePflag = data[off + ndx];
566 					    ndx += 1;
567 
568 					    persVal = dwarf_ehe_extract(
569 						&data[off],
570 						&ndx, ciePflag, ehdr->e_ident,
571 						shdr->sh_addr + off + ndx);
572 					    dbg_print(0,
573 						MSG_ORIG(MSG_UNW_CIEAUXPERS),
574 						ciePflag,
575 						conv_dwarf_ehe(ciePflag),
576 						EC_XWORD(persVal));
577 					    break;
578 					case 'R':
579 					    val = data[off + ndx];
580 					    ndx += 1;
581 					    dbg_print(0,
582 						MSG_ORIG(MSG_UNW_CIEAUXCENC),
583 						val, conv_dwarf_ehe(val));
584 					    cieRflag = val;
585 					    break;
586 					case 'L':
587 					    val = data[off + ndx];
588 					    ndx += 1;
589 					    dbg_print(0,
590 						MSG_ORIG(MSG_UNW_CIEAUXLSDA),
591 						val, conv_dwarf_ehe(val));
592 					    cieLflag = val;
593 					    break;
594 					default:
595 					    dbg_print(0,
596 						MSG_ORIG(MSG_UNW_CIEAUXUNEC),
597 						cieaugstr[cieaugndx]);
598 					    break;
599 					}
600 				}
601 				if ((cielength + 4) > ndx)
602 					unwindtbl(&ndx, cielength, data, off,
603 					    MSG_ORIG(MSG_UNW_CIECFI),
604 					    MSG_ORIG(MSG_UNW_CIEPRE),
605 					    MSG_UNW_CIEPRE_SIZE);
606 				off += cielength + 4;
607 
608 			} else {
609 				uint_t	    fdelength = length;
610 				int	    fdecieptr = id;
611 				uint64_t    fdeinitloc, fdeaddrrange;
612 
613 				dbg_print(0, MSG_ORIG(MSG_UNW_FDE),
614 				    EC_XWORD(shdr->sh_addr + off));
615 				dbg_print(0, MSG_ORIG(MSG_UNW_FDELNGTH),
616 				    fdelength, fdecieptr);
617 
618 				fdeinitloc = dwarf_ehe_extract(&data[off],
619 				    &ndx, cieRflag, ehdr->e_ident,
620 				    shdr->sh_addr + off + ndx);
621 				fdeaddrrange = dwarf_ehe_extract(&data[off],
622 				    &ndx, (cieRflag & ~DW_EH_PE_pcrel),
623 				    ehdr->e_ident,
624 				    shdr->sh_addr + off + ndx);
625 
626 				dbg_print(0, MSG_ORIG(MSG_UNW_FDEINITLOC),
627 				    EC_XWORD(fdeinitloc),
628 				    EC_XWORD(fdeaddrrange));
629 
630 				if (cieaugstr[0])
631 					dbg_print(0,
632 					    MSG_ORIG(MSG_UNW_FDEAUXVAL));
633 				if (cieZflag) {
634 					uint64_t    val;
635 					val = uleb_extract(&data[off], &ndx);
636 					dbg_print(0,
637 					    MSG_ORIG(MSG_UNW_FDEAUXSIZE),
638 					    EC_XWORD(val));
639 					if (val & cieLflag) {
640 					    fdeinitloc = dwarf_ehe_extract(
641 						&data[off], &ndx, cieLflag,
642 						ehdr->e_ident,
643 						shdr->sh_addr + off + ndx);
644 					    dbg_print(0,
645 						MSG_ORIG(MSG_UNW_FDEAUXLSDA),
646 						EC_XWORD(val));
647 					}
648 				}
649 				if ((fdelength + 4) > ndx)
650 					unwindtbl(&ndx, fdelength, data, off,
651 					    MSG_ORIG(MSG_UNW_FDECFI),
652 					    MSG_ORIG(MSG_UNW_FDEPRE),
653 					    MSG_UNW_FDEPRE_SIZE);
654 				off += fdelength + 4;
655 			}
656 		}
657 	}
658 }
659 
660 /*
661  * Print the hardware/software capabilities.  For executables and shared objects
662  * this should be accompanied with a program header.
663  */
664 static void
665 cap(const char *file, Cache *cache, Word shnum, Word phnum, Ehdr *ehdr,
666     Elf *elf)
667 {
668 	Word		cnt;
669 	Shdr		*cshdr = 0;
670 	Cache		*ccache;
671 	Off		cphdr_off = 0;
672 	Xword		cphdr_sz;
673 
674 	/*
675 	 * Determine if a hardware/software capabilities header exists.
676 	 */
677 	if (phnum) {
678 		Phdr	*phdr;
679 
680 		if ((phdr = elf_getphdr(elf)) == NULL) {
681 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
682 			return;
683 		}
684 
685 		for (cnt = 0; cnt < phnum; phdr++, cnt++) {
686 			if (phdr->p_type == PT_SUNWCAP) {
687 				cphdr_off = phdr->p_offset;
688 				cphdr_sz = phdr->p_filesz;
689 				break;
690 			}
691 		}
692 	}
693 
694 	/*
695 	 * Determine if a hardware/software capabilities section exists.
696 	 */
697 	for (cnt = 1; cnt < shnum; cnt++) {
698 		Cache	*_cache = &cache[cnt];
699 		Shdr	*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 		if (_cache->c_data == NULL)
709 			continue;
710 
711 		ccache = _cache;
712 		cshdr = shdr;
713 		break;
714 	}
715 
716 	if ((cshdr == 0) && (cphdr_off == 0))
717 		return;
718 
719 	if ((cshdr->sh_entsize == 0) || (cshdr->sh_size == 0)) {
720 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
721 		    file, ccache->c_name);
722 		return;
723 	}
724 
725 	/*
726 	 * Print the hardware/software capabilities section.
727 	 */
728 	if (cshdr) {
729 		Word	ndx, capn;
730 		Cap	*cap = (Cap *)ccache->c_data->d_buf;
731 
732 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
733 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_CAP), ccache->c_name);
734 
735 		Elf_cap_title(0);
736 
737 		capn = (Word)(cshdr->sh_size / cshdr->sh_entsize);
738 
739 		for (ndx = 0; ndx < capn; cap++, ndx++) {
740 			if (cap->c_tag != CA_SUNW_NULL)
741 				Elf_cap_entry(0, 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, Word shnum, Word phnum, Elf *elf)
767 {
768 	Word	cnt;
769 	Shdr	*ishdr = 0;
770 	Cache	*icache;
771 	Off	iphdr_off = 0;
772 	Xword	iphdr_fsz;
773 
774 	/*
775 	 * Determine if an interp header exists.
776 	 */
777 	if (phnum) {
778 		Phdr	*phdr;
779 
780 		if ((phdr = getphdr(phnum, PT_INTERP, file, elf)) != 0) {
781 			iphdr_off = phdr->p_offset;
782 			iphdr_fsz = phdr->p_filesz;
783 		}
784 	}
785 
786 	if (iphdr_off == 0)
787 		return;
788 
789 	/*
790 	 * Determine if an interp section exists.
791 	 */
792 	for (cnt = 1; cnt < shnum; cnt++) {
793 		Cache	*_cache = &cache[cnt];
794 		Shdr	*shdr = _cache->c_shdr;
795 
796 		/*
797 		 * Scan sections to find a section which contains the PT_INTERP
798 		 * string.  The target section can't be in a NOBITS section.
799 		 */
800 		if ((shdr->sh_type == SHT_NOBITS) ||
801 		    (iphdr_off < shdr->sh_offset) ||
802 		    (iphdr_off + iphdr_fsz) > (shdr->sh_offset + shdr->sh_size))
803 			continue;
804 
805 		icache = _cache;
806 		ishdr = shdr;
807 		break;
808 	}
809 
810 	/*
811 	 * Print the interpreter string based on the offset defined in the
812 	 * program header, as this is the offset used by the kernel.
813 	 */
814 	if (ishdr && icache->c_data) {
815 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
816 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_INTERP), icache->c_name);
817 		dbg_print(0, MSG_ORIG(MSG_FMT_INDENT),
818 		    (char *)icache->c_data->d_buf +
819 		    (iphdr_off - ishdr->sh_offset));
820 	} else
821 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP1), file);
822 
823 	/*
824 	 * If there are any inconsistences between the program header and
825 	 * section information, flag them.
826 	 */
827 	if (ishdr && ((iphdr_off != ishdr->sh_offset) ||
828 	    (iphdr_fsz != ishdr->sh_size))) {
829 		(void) fprintf(stderr, MSG_INTL(MSG_WARN_INVINTERP2), file,
830 		    icache->c_name);
831 	}
832 }
833 
834 /*
835  * Print the syminfo section.
836  */
837 static void
838 syminfo(Cache *cache, Word shnum, const char *file)
839 {
840 	Shdr		*infoshdr;
841 	Syminfo		*info;
842 	Sym		*syms;
843 	Dyn		*dyns;
844 	Word		infonum, cnt, ndx, symnum;
845 	Cache		*infocache = 0, *symsec, *strsec;
846 
847 	for (cnt = 1; cnt < shnum; cnt++) {
848 		if (cache[cnt].c_shdr->sh_type == SHT_SUNW_syminfo) {
849 			infocache = &cache[cnt];
850 			break;
851 		}
852 	}
853 	if (infocache == 0)
854 		return;
855 
856 	infoshdr = infocache->c_shdr;
857 	if ((infoshdr->sh_entsize == 0) || (infoshdr->sh_size == 0)) {
858 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
859 		    file, infocache->c_name);
860 		return;
861 	}
862 	if (infocache->c_data == NULL)
863 		return;
864 
865 	infonum = (Word)(infoshdr->sh_size / infoshdr->sh_entsize);
866 	info = (Syminfo *)infocache->c_data->d_buf;
867 
868 	/*
869 	 * Get the data buffer of the associated dynamic section.
870 	 */
871 	if ((infoshdr->sh_info == 0) || (infoshdr->sh_info >= shnum)) {
872 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
873 		    file, infocache->c_name, EC_WORD(infoshdr->sh_info));
874 		return;
875 	}
876 	if (cache[infoshdr->sh_info].c_data == NULL)
877 		return;
878 
879 	dyns = cache[infoshdr->sh_info].c_data->d_buf;
880 	if (dyns == 0) {
881 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
882 		    file, cache[infoshdr->sh_info].c_name);
883 		return;
884 	}
885 
886 	/*
887 	 * Get the data buffer for the associated symbol table and string table.
888 	 */
889 	if (stringtbl(cache, 1, cnt, shnum, file,
890 	    &symnum, &symsec, &strsec) == 0)
891 		return;
892 
893 	syms = symsec->c_data->d_buf;
894 
895 	/*
896 	 * Loop through the syminfo entries.
897 	 */
898 	dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
899 	dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMINFO), infocache->c_name);
900 	Elf_syminfo_title(0);
901 
902 	for (ndx = 1, info++; ndx < infonum; ndx++, info++) {
903 		Sym 		*sym;
904 		const char	*needed = 0, *name;
905 
906 		if ((info->si_flags == 0) && (info->si_boundto == 0))
907 			continue;
908 
909 		sym = &syms[ndx];
910 		name = string(infocache, ndx, strsec, file, sym->st_name);
911 
912 		if (info->si_boundto < SYMINFO_BT_LOWRESERVE) {
913 			Dyn	*dyn = &dyns[info->si_boundto];
914 
915 			needed = string(infocache, info->si_boundto,
916 			    strsec, file, dyn->d_un.d_val);
917 		}
918 		Elf_syminfo_entry(0, ndx, info, name, needed);
919 	}
920 }
921 
922 /*
923  * Print version definition section entries.
924  */
925 static void
926 version_def(Verdef *vdf, Word shnum, Cache *vcache, Cache *scache,
927     const char *file)
928 {
929 	Word	cnt;
930 	char	index[MAXNDXSIZE];
931 
932 	Elf_ver_def_title(0);
933 
934 	for (cnt = 1; cnt <= shnum; cnt++,
935 	    vdf = (Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
936 		const char	*name, *dep;
937 		Half		vcnt = vdf->vd_cnt - 1;
938 		Half		ndx = vdf->vd_ndx;
939 		Verdaux		*vdap = (Verdaux *)((uintptr_t)vdf +
940 				    vdf->vd_aux);
941 
942 		/*
943 		 * Obtain the name and first dependency (if any).
944 		 */
945 		name = string(vcache, cnt, scache, file, vdap->vda_name);
946 		vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
947 		if (vcnt)
948 			dep = string(vcache, cnt, scache, file, vdap->vda_name);
949 		else
950 			dep = MSG_ORIG(MSG_STR_EMPTY);
951 
952 		(void) snprintf(index, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX),
953 		    EC_XWORD(ndx));
954 		Elf_ver_line_1(0, index, name, dep,
955 		    conv_ver_flags(vdf->vd_flags));
956 
957 		/*
958 		 * Print any additional dependencies.
959 		 */
960 		if (vcnt) {
961 			vdap = (Verdaux *)((uintptr_t)vdap + vdap->vda_next);
962 			for (vcnt--; vcnt; vcnt--,
963 			    vdap = (Verdaux *)((uintptr_t)vdap +
964 			    vdap->vda_next)) {
965 				dep = string(vcache, cnt, scache, file,
966 				    vdap->vda_name);
967 				Elf_ver_line_2(0, MSG_ORIG(MSG_STR_EMPTY), dep);
968 			}
969 		}
970 	}
971 }
972 
973 /*
974  * Print a version needed section entries.
975  */
976 static void
977 version_need(Verneed *vnd, Word shnum, Cache *vcache, Cache *scache,
978     const char *file)
979 {
980 	Word	cnt;
981 
982 	Elf_ver_need_title(0);
983 
984 	for (cnt = 1; cnt <= shnum; cnt++,
985 	    vnd = (Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
986 		const char	*name, *dep;
987 		Half		vcnt = vnd->vn_cnt;
988 		Vernaux		*vnap = (Vernaux *)((uintptr_t)vnd +
989 					vnd->vn_aux);
990 
991 		/*
992 		 * Obtain the name of the needed file and the version name
993 		 * within it that we're dependent on.  Note that the count
994 		 * should be at least one, otherwise this is a pretty bogus
995 		 * entry.
996 		 */
997 		name = string(vcache, cnt, scache, file, vnd->vn_file);
998 		if (vcnt)
999 			dep = string(vcache, cnt, scache, file, vnap->vna_name);
1000 		else
1001 			dep = MSG_INTL(MSG_STR_NULL);
1002 
1003 		Elf_ver_line_1(0, MSG_ORIG(MSG_STR_EMPTY), name, dep,
1004 		    conv_ver_flags(vnap->vna_flags));
1005 
1006 		/*
1007 		 * Print any additional version dependencies.
1008 		 */
1009 		if (vcnt) {
1010 			vnap = (Vernaux *)((uintptr_t)vnap + vnap->vna_next);
1011 			for (vcnt--; vcnt; vcnt--,
1012 			    vnap = (Vernaux *)((uintptr_t)vnap +
1013 			    vnap->vna_next)) {
1014 				dep = string(vcache, cnt, scache, file,
1015 				    vnap->vna_name);
1016 				Elf_ver_line_3(0, MSG_ORIG(MSG_STR_EMPTY), dep,
1017 				    conv_ver_flags(vnap->vna_flags));
1018 			}
1019 		}
1020 	}
1021 }
1022 
1023 /*
1024  * Display version section information if the flags require it.
1025  * Return version information needed by other output.
1026  *
1027  * entry:
1028  *	cache - Cache of all section headers
1029  *	shnum - # of sections in cache
1030  *	file - Name of file
1031  *	flags - Command line option flags
1032  *	versym - VERSYM_STATE block to be filled in.
1033  */
1034 static void
1035 versions(Cache *cache, Word shnum, const char *file, uint_t flags,
1036     VERSYM_STATE *versym)
1037 {
1038 	GElf_Word	cnt;
1039 	const char	*gnu_prefix;
1040 	size_t		gnu_prefix_len;
1041 
1042 	bzero(versym, sizeof (*versym));
1043 	gnu_prefix = MSG_ORIG(MSG_GNU_VERNAMPREFIX);
1044 	gnu_prefix_len = strlen(gnu_prefix);
1045 
1046 	for (cnt = 1; cnt < shnum; cnt++) {
1047 		void		*ver;
1048 		uint_t		num;
1049 		Cache		*_cache = &cache[cnt];
1050 		Shdr		*shdr = _cache->c_shdr;
1051 		const char	*secname = _cache->c_name;
1052 
1053 		/*
1054 		 * If the section names starts with the .gnu.version prefix,
1055 		 * then this object was almost certainly produced by the
1056 		 * GNU ld and not the native Solaris ld.
1057 		 */
1058 		if (strncmp(gnu_prefix, secname, gnu_prefix_len) == 0)
1059 			versym->gnu = 1;
1060 
1061 		/*
1062 		 * If this is the version symbol table record its data
1063 		 * address for later symbol processing.
1064 		 */
1065 		if ((shdr->sh_type == SHT_SUNW_versym) &&
1066 		    (_cache->c_data != NULL)) {
1067 			versym->cache = _cache;
1068 			versym->data = _cache->c_data->d_buf;
1069 			continue;
1070 		}
1071 
1072 		/*
1073 		 * If this is a version definition section, retain # of
1074 		 * version definitions for later symbol processing.
1075 		 */
1076 		if (shdr->sh_type == SHT_SUNW_verdef)
1077 			versym->num_verdef = shdr->sh_info;
1078 
1079 		if ((flags & FLG_VERSIONS) == 0)
1080 			continue;
1081 
1082 		if ((shdr->sh_type != SHT_SUNW_verdef) &&
1083 		    (shdr->sh_type != SHT_SUNW_verneed))
1084 			continue;
1085 
1086 		/*
1087 		 * Determine the version section data and number.
1088 		 */
1089 		if ((_cache->c_data == NULL) ||
1090 		    ((ver = (void *)_cache->c_data->d_buf) == NULL)) {
1091 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1092 			    file, secname);
1093 			continue;
1094 		}
1095 		if ((num = shdr->sh_info) == 0) {
1096 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
1097 			    file, secname, EC_WORD(shdr->sh_info));
1098 			continue;
1099 		}
1100 
1101 		/*
1102 		 * Get the data buffer for the associated string table.
1103 		 */
1104 		if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1105 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1106 			    file, secname, EC_WORD(shdr->sh_link));
1107 			continue;
1108 		}
1109 
1110 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1111 		if (shdr->sh_type == SHT_SUNW_verdef) {
1112 			dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERDEF), secname);
1113 			version_def((Verdef *)ver, num, _cache,
1114 			    &cache[shdr->sh_link], file);
1115 		} else if (shdr->sh_type == SHT_SUNW_verneed) {
1116 			dbg_print(0, MSG_INTL(MSG_ELF_SCN_VERNEED), secname);
1117 			version_need((Verneed *)ver, num, _cache,
1118 			    &cache[shdr->sh_link], file);
1119 		}
1120 	}
1121 }
1122 
1123 /*
1124  * Initialize a symbol table state structure
1125  *
1126  * entry:
1127  *	state - State structure to be initialized
1128  *	cache - Cache of all section headers
1129  *	shnum - # of sections in cache
1130  *	secndx - Index of symbol table section
1131  *	ehdr - ELF header for file
1132  *	versym - Information about versym section
1133  *	file - Name of file
1134  *	flags - Command line option flags
1135  */
1136 static int
1137 init_symtbl_state(SYMTBL_STATE *state, Cache *cache, Word shnum, Word secndx,
1138     Ehdr *ehdr, VERSYM_STATE *versym, const char *file, uint_t flags)
1139 {
1140 	Shdr *shdr;
1141 
1142 	state->file = file;
1143 	state->ehdr = ehdr;
1144 	state->cache = cache;
1145 	state->shnum = shnum;
1146 	state->seccache = &cache[secndx];
1147 	state->secndx = secndx;
1148 	state->secname = state->seccache->c_name;
1149 	state->flags = flags;
1150 	state->shxndx.checked = 0;
1151 	state->shxndx.data = NULL;
1152 	state->shxndx.n = 0;
1153 
1154 	shdr = state->seccache->c_shdr;
1155 
1156 	/*
1157 	 * Check the symbol data and per-item size.
1158 	 */
1159 	if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
1160 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1161 		    file, state->secname);
1162 		return (0);
1163 	}
1164 	if (state->seccache->c_data == NULL)
1165 		return (0);
1166 
1167 	/* LINTED */
1168 	state->symn = (Word)(shdr->sh_size / shdr->sh_entsize);
1169 	state->sym = (Sym *)state->seccache->c_data->d_buf;
1170 
1171 	/*
1172 	 * Check associated string table section.
1173 	 */
1174 	if ((shdr->sh_link == 0) || (shdr->sh_link >= shnum)) {
1175 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1176 		    file, state->secname, EC_WORD(shdr->sh_link));
1177 		return (0);
1178 	}
1179 
1180 	/*
1181 	 * Determine if there is a associated Versym section
1182 	 * with this Symbol Table.
1183 	 */
1184 	if (versym->cache &&
1185 	    (versym->cache->c_shdr->sh_link == state->secndx))
1186 		state->versym = versym;
1187 	else
1188 		state->versym = NULL;
1189 
1190 
1191 	return (1);
1192 }
1193 
1194 /*
1195  * Determine the extended section index used for symbol tables entries.
1196  */
1197 static void
1198 symbols_getxindex(SYMTBL_STATE * state)
1199 {
1200 	uint_t	symn;
1201 	Word	symcnt;
1202 
1203 	state->shxndx.checked = 1;   /* Note that we've been called */
1204 	for (symcnt = 1; symcnt < state->shnum; symcnt++) {
1205 		Cache	*_cache = &state->cache[symcnt];
1206 		Shdr	*shdr = _cache->c_shdr;
1207 
1208 		if ((shdr->sh_type != SHT_SYMTAB_SHNDX) ||
1209 		    (shdr->sh_link != state->secndx))
1210 			continue;
1211 
1212 		if ((shdr->sh_entsize) &&
1213 		    /* LINTED */
1214 		    ((symn = (uint_t)(shdr->sh_size / shdr->sh_entsize)) == 0))
1215 			continue;
1216 
1217 		if (_cache->c_data == NULL)
1218 			continue;
1219 
1220 		state->shxndx.data = _cache->c_data->d_buf;
1221 		state->shxndx.n = symn;
1222 		return;
1223 	}
1224 }
1225 
1226 /*
1227  * Produce a line of output for the given symbol
1228  *
1229  * entry:
1230  *	state - Symbol table state
1231  *	symndx - Index of symbol within the table
1232  *	symndx_disp - Index to display. This may not be the same
1233  *		as symndx if the display is relative to the logical
1234  *		combination of the SUNW_ldynsym/dynsym tables.
1235  *	sym - Symbol to display
1236  */
1237 static void
1238 output_symbol(SYMTBL_STATE *state, Word symndx, Word disp_symndx, Sym *sym)
1239 {
1240 	/*
1241 	 * Symbol types for which we check that the specified
1242 	 * address/size land inside the target section.
1243 	 */
1244 	static const int addr_symtype[STT_NUM] = {
1245 		0,			/* STT_NOTYPE */
1246 		1,			/* STT_OBJECT */
1247 		1,			/* STT_FUNC */
1248 		0,			/* STT_SECTION */
1249 		0,			/* STT_FILE */
1250 		1,			/* STT_COMMON */
1251 		0,			/* STT_TLS */
1252 	};
1253 #if STT_NUM != (STT_TLS + 1)
1254 #error "STT_NUM has grown. Update addr_symtype[]"
1255 #endif
1256 
1257 	char		index[MAXNDXSIZE], *sec;
1258 	const char	*symname;
1259 	Versym		verndx;
1260 	uchar_t		type;
1261 	Shdr		*tshdr;
1262 	Word		shndx;
1263 
1264 	/* Ensure symbol index is in range */
1265 	if (symndx >= state->symn) {
1266 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSORTNDX),
1267 		    state->file, state->secname, EC_WORD(symndx));
1268 		return;
1269 	}
1270 
1271 	/*
1272 	 * If we are using extended symbol indexes, find the
1273 	 * corresponding SHN_SYMTAB_SHNDX table.
1274 	 */
1275 	if ((sym->st_shndx == SHN_XINDEX) && (state->shxndx.checked == 0))
1276 		symbols_getxindex(state);
1277 
1278 	/* LINTED */
1279 	symname = string(state->seccache, symndx,
1280 	    &state->cache[state->seccache->c_shdr->sh_link], state->file,
1281 	    sym->st_name);
1282 
1283 	tshdr = 0;
1284 	sec = NULL;
1285 
1286 	if ((state->ehdr->e_type == ET_CORE))
1287 		sec = (char *)MSG_INTL(MSG_STR_UNKNOWN);
1288 	else if ((sym->st_shndx < SHN_LORESERVE) &&
1289 	    (sym->st_shndx < state->shnum)) {
1290 		shndx = sym->st_shndx;
1291 		tshdr = state->cache[shndx].c_shdr;
1292 		sec = state->cache[shndx].c_name;
1293 	} else if (sym->st_shndx == SHN_XINDEX) {
1294 		if (state->shxndx.data) {
1295 			Word	_shxndx;
1296 
1297 			if (symndx > state->shxndx.n) {
1298 			    (void) fprintf(stderr,
1299 				MSG_INTL(MSG_ERR_BADSYMXINDEX1),
1300 				state->file, state->secname, EC_WORD(symndx));
1301 			} else if ((_shxndx =
1302 			    state->shxndx.data[symndx]) > state->shnum) {
1303 			    (void) fprintf(stderr,
1304 				MSG_INTL(MSG_ERR_BADSYMXINDEX2),
1305 				state->file, state->secname, EC_WORD(symndx),
1306 				EC_WORD(_shxndx));
1307 			} else {
1308 			    shndx = _shxndx;
1309 			    tshdr = state->cache[shndx].c_shdr;
1310 			    sec = state->cache[shndx].c_name;
1311 			}
1312 		} else {
1313 			(void) fprintf(stderr,
1314 			    MSG_INTL(MSG_ERR_BADSYMXINDEX3),
1315 			    state->file, state->secname, EC_WORD(symndx));
1316 		}
1317 	} else if ((sym->st_shndx < SHN_LORESERVE) &&
1318 	    (sym->st_shndx >= state->shnum)) {
1319 		(void) fprintf(stderr,
1320 		    MSG_INTL(MSG_ERR_BADSYM5), state->file,
1321 		    state->secname, demangle(symname, state->flags),
1322 		    sym->st_shndx);
1323 	}
1324 
1325 	/*
1326 	 * If versioning is available display the
1327 	 * version index. If not, then use 0.
1328 	 */
1329 	if (state->versym) {
1330 		verndx = state->versym->data[symndx];
1331 
1332 		/*
1333 		 * Check to see if this is a defined symbol with a
1334 		 * version index that is outside the valid range for
1335 		 * the file. If so, then there are two possiblities:
1336 		 *
1337 		 *	- Files produced by the GNU ld use the top (16th) bit
1338 		 *		as a "hidden symbol" marker. If we have
1339 		 *		detected that this object comes from GNU ld,
1340 		 *		then check to see if this is the case and that
1341 		 *		the resulting masked version is in range. If so,
1342 		 *		issue a warning describing it.
1343 		 *	- If this is not a GNU "hidden bit" issue, then
1344 		 *		issue a generic "out of range" error.
1345 		 */
1346 		if (VERNDX_INVALID(sym->st_shndx, state->versym->num_verdef,
1347 		    state->versym->data, verndx)) {
1348 			if (state->versym->gnu && (verndx & 0x8000) &&
1349 			    ((verndx & ~0x8000) <=
1350 			    state->versym->num_verdef)) {
1351 				(void) fprintf(stderr,
1352 				    MSG_INTL(MSG_WARN_GNUVER), state->file,
1353 				    state->secname, EC_WORD(symndx),
1354 				    EC_HALF(verndx & ~0x8000));
1355 			} else {	/* Generic version range error */
1356 				(void) fprintf(stderr,
1357 				    MSG_INTL(MSG_ERR_BADVER), state->file,
1358 				    state->secname, EC_WORD(symndx),
1359 				    EC_HALF(verndx), state->versym->num_verdef);
1360 			}
1361 		}
1362 	} else {
1363 		verndx = 0;
1364 	}
1365 
1366 	/*
1367 	 * Error checking for TLS.
1368 	 */
1369 	type = ELF_ST_TYPE(sym->st_info);
1370 	if (type == STT_TLS) {
1371 		if (tshdr &&
1372 		    (sym->st_shndx != SHN_UNDEF) &&
1373 		    ((tshdr->sh_flags & SHF_TLS) == 0)) {
1374 			(void) fprintf(stderr,
1375 			    MSG_INTL(MSG_ERR_BADSYM3), state->file,
1376 			    state->secname, demangle(symname, state->flags));
1377 		}
1378 	} else if ((type != STT_SECTION) && sym->st_size &&
1379 	    tshdr && (tshdr->sh_flags & SHF_TLS)) {
1380 		(void) fprintf(stderr,
1381 		    MSG_INTL(MSG_ERR_BADSYM4), state->file,
1382 		    state->secname, demangle(symname, state->flags));
1383 	}
1384 
1385 	/*
1386 	 * If a symbol with non-zero size has a type that
1387 	 * specifies an address, then make sure the location
1388 	 * it references is actually contained within the
1389 	 * section.  UNDEF symbols don't count in this case,
1390 	 * so we ignore them.
1391 	 *
1392 	 * The meaning of the st_value field in a symbol
1393 	 * depends on the type of object. For a relocatable
1394 	 * object, it is the offset within the section.
1395 	 * For sharable objects, it is the offset relative to
1396 	 * the base of the object, and for other types, it is
1397 	 * the virtual address. To get an offset within the
1398 	 * section for non-ET_REL files, we subtract the
1399 	 * base address of the section.
1400 	 */
1401 	if (addr_symtype[type] && (sym->st_size > 0) &&
1402 	    (sym->st_shndx != SHN_UNDEF) && ((sym->st_shndx < SHN_LORESERVE) ||
1403 	    (sym->st_shndx == SHN_XINDEX)) && (tshdr != NULL)) {
1404 		Word v = sym->st_value;
1405 			if (state->ehdr->e_type != ET_REL)
1406 			v -= tshdr->sh_addr;
1407 		if (((v + sym->st_size) > tshdr->sh_size)) {
1408 			(void) fprintf(stderr,
1409 			    MSG_INTL(MSG_ERR_BADSYM6), state->file,
1410 			    state->secname, demangle(symname, state->flags),
1411 			    EC_WORD(shndx), EC_XWORD(tshdr->sh_size),
1412 			    EC_XWORD(sym->st_value), EC_XWORD(sym->st_size));
1413 		}
1414 	}
1415 
1416 	(void) snprintf(index, MAXNDXSIZE,
1417 	    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(disp_symndx));
1418 	Elf_syms_table_entry(0, ELF_DBG_ELFDUMP, index,
1419 	    state->ehdr->e_machine, sym, verndx, sec, symname);
1420 }
1421 
1422 /*
1423  * Search for and process any symbol tables.
1424  */
1425 void
1426 symbols(Cache *cache, Word shnum, Ehdr *ehdr, const char *name,
1427     VERSYM_STATE *versym, const char *file, uint_t flags)
1428 {
1429 	SYMTBL_STATE state;
1430 	Cache *_cache;
1431 	Word secndx;
1432 
1433 	for (secndx = 1; secndx < shnum; secndx++) {
1434 		Word		symcnt;
1435 		Shdr		*shdr;
1436 
1437 		_cache = &cache[secndx];
1438 		shdr = _cache->c_shdr;
1439 
1440 		if ((shdr->sh_type != SHT_SYMTAB) &&
1441 		    (shdr->sh_type != SHT_DYNSYM) &&
1442 		    (shdr->sh_type != SHT_SUNW_LDYNSYM))
1443 			continue;
1444 		if (name && strcmp(name, _cache->c_name))
1445 			continue;
1446 
1447 		if (!init_symtbl_state(&state, cache, shnum, secndx, ehdr,
1448 		    versym, file, flags))
1449 			continue;
1450 		/*
1451 		 * Loop through the symbol tables entries.
1452 		 */
1453 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1454 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMTAB), state.secname);
1455 		Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
1456 
1457 		for (symcnt = 0; symcnt < state.symn; symcnt++)
1458 			output_symbol(&state, symcnt, symcnt,
1459 			    state.sym + symcnt);
1460 	}
1461 }
1462 
1463 /*
1464  * Search for and process any SHT_SUNW_symsort or SHT_SUNW_tlssort sections.
1465  * These sections are always associated with the .SUNW_ldynsym./.dynsym pair.
1466  */
1467 static void
1468 sunw_sort(Cache *cache, Word shnum, Ehdr *ehdr, const char *name,
1469     VERSYM_STATE *versym, const char *file, uint_t flags)
1470 {
1471 	SYMTBL_STATE	ldynsym_state,	dynsym_state;
1472 	Cache		*sortcache,	*symcache;
1473 	Shdr		*sortshdr,	*symshdr;
1474 	Word		sortsecndx,	symsecndx;
1475 	Word		ldynsym_cnt;
1476 	Word		*ndx;
1477 	Word		ndxn;
1478 	int		output_cnt = 0;
1479 
1480 	for (sortsecndx = 1; sortsecndx < shnum; sortsecndx++) {
1481 
1482 		sortcache = &cache[sortsecndx];
1483 		sortshdr = sortcache->c_shdr;
1484 
1485 		if ((sortshdr->sh_type != SHT_SUNW_symsort) &&
1486 		    (sortshdr->sh_type != SHT_SUNW_tlssort))
1487 			continue;
1488 		if (name && strcmp(name, sortcache->c_name))
1489 			continue;
1490 
1491 		/*
1492 		 * If the section references a SUNW_ldynsym, then we
1493 		 * expect to see the associated .dynsym immediately
1494 		 * following. If it references a .dynsym, there is no
1495 		 * SUNW_ldynsym. If it is any other type, then we don't
1496 		 * know what to do with it.
1497 		 */
1498 		if ((sortshdr->sh_link == 0) || (sortshdr->sh_link >= shnum)) {
1499 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
1500 			    file, sortcache->c_name,
1501 			    EC_WORD(sortshdr->sh_link));
1502 			continue;
1503 		}
1504 		symcache = &cache[sortshdr->sh_link];
1505 		symshdr = symcache->c_shdr;
1506 		symsecndx = sortshdr->sh_link;
1507 		ldynsym_cnt = 0;
1508 		switch (symshdr->sh_type) {
1509 		case SHT_SUNW_LDYNSYM:
1510 			if (!init_symtbl_state(&ldynsym_state, cache, shnum,
1511 			    symsecndx, ehdr, versym, file, flags))
1512 				continue;
1513 			ldynsym_cnt = ldynsym_state.symn;
1514 			/*
1515 			 * We know that the dynsym follows immediately
1516 			 * after the SUNW_ldynsym, and so, should be at
1517 			 * (sortshdr->sh_link + 1). However, elfdump is a
1518 			 * diagnostic tool, so we do the full paranoid
1519 			 * search instead.
1520 			 */
1521 			for (symsecndx = 1; symsecndx < shnum; symsecndx++) {
1522 				symcache = &cache[symsecndx];
1523 				symshdr = symcache->c_shdr;
1524 				if (symshdr->sh_type == SHT_DYNSYM)
1525 					break;
1526 			}
1527 			if (symsecndx >= shnum) {	/* Dynsym not found! */
1528 				(void) fprintf(stderr,
1529 				    MSG_INTL(MSG_ERR_NODYNSYM),
1530 				    file, sortcache->c_name);
1531 				continue;
1532 			}
1533 			/* Fallthrough to process associated dynsym */
1534 			/*FALLTHROUGH*/
1535 		case SHT_DYNSYM:
1536 			if (!init_symtbl_state(&dynsym_state, cache, shnum,
1537 			    symsecndx, ehdr, versym, file, flags))
1538 				continue;
1539 			break;
1540 		default:
1541 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADNDXSEC),
1542 			    file, sortcache->c_name, conv_sec_type(
1543 			    ehdr->e_machine, symshdr->sh_type, 0));
1544 			continue;
1545 		}
1546 
1547 		/*
1548 		 * Output header
1549 		 */
1550 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1551 		if (ldynsym_cnt > 0) {
1552 			dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT2),
1553 			    sortcache->c_name, ldynsym_state.secname,
1554 			    dynsym_state.secname);
1555 			/*
1556 			 * The data for .SUNW_ldynsym and dynsym sections
1557 			 * is supposed to be adjacent with SUNW_ldynsym coming
1558 			 * first. Check, and issue a warning if it isn't so.
1559 			 */
1560 			if ((ldynsym_state.sym + ldynsym_state.symn)
1561 			    != dynsym_state.sym)
1562 				(void) fprintf(stderr,
1563 				    MSG_INTL(MSG_ERR_LDYNNOTADJ), file,
1564 				    ldynsym_state.secname,
1565 				    dynsym_state.secname);
1566 		} else {
1567 			dbg_print(0, MSG_INTL(MSG_ELF_SCN_SYMSORT1),
1568 			    sortcache->c_name, dynsym_state.secname);
1569 		}
1570 		Elf_syms_table_title(0, ELF_DBG_ELFDUMP);
1571 
1572 		/* If not first one, insert a line of whitespace */
1573 		if (output_cnt++ > 0)
1574 			dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1575 
1576 		/*
1577 		 * SUNW_dynsymsort and SUNW_dyntlssort are arrays of
1578 		 * symbol indices. Iterate over the array entries,
1579 		 * dispaying the referenced symbols.
1580 		 */
1581 		ndxn = sortshdr->sh_size / sortshdr->sh_entsize;
1582 		ndx = (Word *)sortcache->c_data->d_buf;
1583 		for (; ndxn-- > 0; ndx++) {
1584 			if (*ndx >= ldynsym_cnt) {
1585 				Word sec_ndx = *ndx - ldynsym_cnt;
1586 
1587 				output_symbol(&dynsym_state, sec_ndx,
1588 				    *ndx, dynsym_state.sym + sec_ndx);
1589 			} else {
1590 				output_symbol(&ldynsym_state, *ndx,
1591 				    *ndx, ldynsym_state.sym + *ndx);
1592 			}
1593 		}
1594 	}
1595 }
1596 
1597 /*
1598  * Search for and process any relocation sections.
1599  */
1600 static void
1601 reloc(Cache *cache, Word shnum, Ehdr *ehdr, const char *name, const char *file,
1602     uint_t flags)
1603 {
1604 	Word	cnt;
1605 
1606 	for (cnt = 1; cnt < shnum; cnt++) {
1607 		Word		type, symnum;
1608 		Xword		relndx, relnum, relsize;
1609 		void		*rels;
1610 		Sym		*syms;
1611 		Cache		*symsec, *strsec;
1612 		Cache		*_cache = &cache[cnt];
1613 		Shdr		*shdr = _cache->c_shdr;
1614 		char		*relname = _cache->c_name;
1615 
1616 		if (((type = shdr->sh_type) != SHT_RELA) &&
1617 		    (type != SHT_REL))
1618 			continue;
1619 		if (name && strcmp(name, relname))
1620 			continue;
1621 
1622 		/*
1623 		 * Decide entry size.
1624 		 */
1625 		if (((relsize = shdr->sh_entsize) == 0) ||
1626 		    (relsize > shdr->sh_size)) {
1627 			if (type == SHT_RELA)
1628 				relsize = sizeof (Rela);
1629 			else
1630 				relsize = sizeof (Rel);
1631 		}
1632 
1633 		/*
1634 		 * Determine the number of relocations available.
1635 		 */
1636 		if (shdr->sh_size == 0) {
1637 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1638 			    file, relname);
1639 			continue;
1640 		}
1641 		if (_cache->c_data == NULL)
1642 			continue;
1643 
1644 		rels = _cache->c_data->d_buf;
1645 		relnum = shdr->sh_size / relsize;
1646 
1647 		/*
1648 		 * Get the data buffer for the associated symbol table and
1649 		 * string table.
1650 		 */
1651 		if (stringtbl(cache, 1, cnt, shnum, file,
1652 		    &symnum, &symsec, &strsec) == 0)
1653 			continue;
1654 
1655 		syms = symsec->c_data->d_buf;
1656 
1657 		/*
1658 		 * Loop through the relocation entries.
1659 		 */
1660 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1661 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_RELOC), _cache->c_name);
1662 		Elf_reloc_title(0, ELF_DBG_ELFDUMP, type);
1663 
1664 		for (relndx = 0; relndx < relnum; relndx++,
1665 		    rels = (void *)((char *)rels + relsize)) {
1666 			char		section[BUFSIZ];
1667 			const char	*symname;
1668 			Word		symndx, reltype;
1669 			Rela		*rela;
1670 			Rel		*rel;
1671 
1672 			/*
1673 			 * Unravel the relocation and determine the symbol with
1674 			 * which this relocation is associated.
1675 			 */
1676 			if (type == SHT_RELA) {
1677 				rela = (Rela *)rels;
1678 				symndx = ELF_R_SYM(rela->r_info);
1679 				reltype = ELF_R_TYPE(rela->r_info);
1680 			} else {
1681 				rel = (Rel *)rels;
1682 				symndx = ELF_R_SYM(rel->r_info);
1683 				reltype = ELF_R_TYPE(rel->r_info);
1684 			}
1685 
1686 			symname = relsymname(cache, _cache, strsec, symndx,
1687 			    symnum, relndx, syms, section, BUFSIZ, file,
1688 			    flags);
1689 
1690 			/*
1691 			 * A zero symbol index is only valid for a few
1692 			 * relocations.
1693 			 */
1694 			if (symndx == 0) {
1695 				Half	mach = ehdr->e_machine;
1696 				int	badrel = 0;
1697 
1698 				if ((mach == EM_SPARC) ||
1699 				    (mach == EM_SPARC32PLUS) ||
1700 				    (mach == EM_SPARCV9)) {
1701 					if ((reltype != R_SPARC_NONE) &&
1702 					    (reltype != R_SPARC_REGISTER) &&
1703 					    (reltype != R_SPARC_RELATIVE))
1704 						badrel++;
1705 				} else if (mach == EM_386) {
1706 					if ((reltype != R_386_NONE) &&
1707 					    (reltype != R_386_RELATIVE))
1708 						badrel++;
1709 				} else if (mach == EM_AMD64) {
1710 					if ((reltype != R_AMD64_NONE) &&
1711 					    (reltype != R_AMD64_RELATIVE))
1712 						badrel++;
1713 				}
1714 
1715 				if (badrel) {
1716 					(void) fprintf(stderr,
1717 					    MSG_INTL(MSG_ERR_BADREL1), file,
1718 					    conv_reloc_type(mach, reltype, 0));
1719 				}
1720 			}
1721 
1722 			Elf_reloc_entry_1(0, ELF_DBG_ELFDUMP,
1723 			    MSG_ORIG(MSG_STR_EMPTY), ehdr->e_machine, type,
1724 			    rels, relname, symname, 0);
1725 		}
1726 	}
1727 }
1728 
1729 /*
1730  * Search for and process a .dynamic section.
1731  */
1732 static void
1733 dynamic(Cache *cache, Word shnum, Ehdr *ehdr, const char *file)
1734 {
1735 	Word	cnt;
1736 
1737 	for (cnt = 1; cnt < shnum; cnt++) {
1738 		Dyn	*dyn;
1739 		ulong_t	numdyn;
1740 		int	ndx, end_ndx;
1741 		Cache	*_cache = &cache[cnt], *strsec;
1742 		Shdr	*shdr = _cache->c_shdr;
1743 
1744 		if (shdr->sh_type != SHT_DYNAMIC)
1745 			continue;
1746 
1747 		/*
1748 		 * Verify the associated string table section.
1749 		 */
1750 		if (stringtbl(cache, 0, cnt, shnum, file, 0, 0, &strsec) == 0)
1751 			continue;
1752 
1753 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
1754 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1755 			    file, _cache->c_name);
1756 			continue;
1757 		}
1758 		if (_cache->c_data == NULL)
1759 			continue;
1760 
1761 		numdyn = shdr->sh_size / shdr->sh_entsize;
1762 		dyn = (Dyn *)_cache->c_data->d_buf;
1763 
1764 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1765 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_DYNAMIC), _cache->c_name);
1766 
1767 		Elf_dyn_title(0);
1768 
1769 		for (ndx = 0; ndx < numdyn; dyn++, ndx++) {
1770 			const char	*name;
1771 
1772 			/*
1773 			 * Print the information numerically, and if possible
1774 			 * as a string.
1775 			 */
1776 			switch (dyn->d_tag) {
1777 			case DT_NULL:
1778 				/*
1779 				 * Special case: DT_NULLs can come in groups
1780 				 * that we prefer to reduce to a single line.
1781 				 */
1782 				end_ndx = ndx;
1783 				while ((end_ndx < (numdyn - 1)) &&
1784 					((dyn + 1)->d_tag == DT_NULL)) {
1785 					dyn++;
1786 					end_ndx++;
1787 				}
1788 				Elf_dyn_null_entry(0, dyn, ndx, end_ndx);
1789 				ndx = end_ndx;
1790 				continue;
1791 
1792 			/*
1793 			 * Print the information numerically, and if possible
1794 			 * as a string.
1795 			 */
1796 			case DT_NEEDED:
1797 			case DT_SONAME:
1798 			case DT_FILTER:
1799 			case DT_AUXILIARY:
1800 			case DT_CONFIG:
1801 			case DT_RPATH:
1802 			case DT_RUNPATH:
1803 			case DT_USED:
1804 			case DT_DEPAUDIT:
1805 			case DT_AUDIT:
1806 			case DT_SUNW_AUXILIARY:
1807 			case DT_SUNW_FILTER:
1808 				name = string(_cache, ndx, strsec,
1809 				    file, dyn->d_un.d_ptr);
1810 				break;
1811 
1812 			case DT_FLAGS:
1813 				name = conv_dyn_flag(dyn->d_un.d_val, 0);
1814 				break;
1815 			case DT_FLAGS_1:
1816 				name = conv_dyn_flag1(dyn->d_un.d_val);
1817 				break;
1818 			case DT_POSFLAG_1:
1819 				name = conv_dyn_posflag1(dyn->d_un.d_val, 0);
1820 				break;
1821 			case DT_FEATURE_1:
1822 				name = conv_dyn_feature1(dyn->d_un.d_val, 0);
1823 				break;
1824 			case DT_DEPRECATED_SPARC_REGISTER:
1825 				name = MSG_INTL(MSG_STR_DEPRECATED);
1826 				break;
1827 			default:
1828 				name = MSG_ORIG(MSG_STR_EMPTY);
1829 				break;
1830 			}
1831 
1832 			Elf_dyn_entry(0, dyn, ndx, name, ehdr->e_machine);
1833 		}
1834 	}
1835 }
1836 
1837 /*
1838  * Search for and process a MOVE section.
1839  */
1840 static void
1841 move(Cache *cache, Word shnum, const char *name, const char *file, uint_t flags)
1842 {
1843 	Word		cnt;
1844 	const char	*fmt = 0;
1845 
1846 	for (cnt = 1; cnt < shnum; cnt++) {
1847 		Word	movenum, symnum, ndx;
1848 		Sym	*syms;
1849 		Cache	*_cache = &cache[cnt];
1850 		Shdr	*shdr = _cache->c_shdr;
1851 		Cache	*symsec, *strsec;
1852 		Move	*move;
1853 
1854 		if (shdr->sh_type != SHT_SUNW_move)
1855 			continue;
1856 		if (name && strcmp(name, _cache->c_name))
1857 			continue;
1858 
1859 		/*
1860 		 * Determine the move data and number.
1861 		 */
1862 		if ((shdr->sh_entsize == 0) || (shdr->sh_size == 0)) {
1863 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
1864 			    file, _cache->c_name);
1865 			continue;
1866 		}
1867 		if (_cache->c_data == NULL)
1868 			continue;
1869 
1870 		move = (Move *)_cache->c_data->d_buf;
1871 		movenum = shdr->sh_size / shdr->sh_entsize;
1872 
1873 		/*
1874 		 * Get the data buffer for the associated symbol table and
1875 		 * string table.
1876 		 */
1877 		if (stringtbl(cache, 1, cnt, shnum, file,
1878 		    &symnum, &symsec, &strsec) == 0)
1879 			return;
1880 
1881 		syms = (Sym *)symsec->c_data->d_buf;
1882 
1883 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
1884 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_MOVE), _cache->c_name);
1885 		dbg_print(0, MSG_INTL(MSG_MOVE_TITLE));
1886 
1887 		if (fmt == 0)
1888 			fmt = MSG_INTL(MSG_MOVE_ENTRY);
1889 
1890 		for (ndx = 0; ndx < movenum; move++, ndx++) {
1891 			const char	*symname;
1892 			char		index[MAXNDXSIZE], section[BUFSIZ];
1893 			Word		symndx, shndx;
1894 			Sym		*sym;
1895 
1896 			/*
1897 			 * Check for null entries
1898 			 */
1899 			if ((move->m_info == 0) && (move->m_value == 0) &&
1900 			    (move->m_poffset == 0) && (move->m_repeat == 0) &&
1901 			    (move->m_stride == 0)) {
1902 				dbg_print(0, fmt, MSG_ORIG(MSG_STR_EMPTY),
1903 				    EC_XWORD(move->m_poffset), 0, 0, 0,
1904 				    EC_LWORD(0), MSG_ORIG(MSG_STR_EMPTY));
1905 				continue;
1906 			}
1907 			if (((symndx = ELF_M_SYM(move->m_info)) == 0) ||
1908 			    (symndx >= symnum)) {
1909 				(void) fprintf(stderr,
1910 				    MSG_INTL(MSG_ERR_BADMINFO), file,
1911 				    _cache->c_name, EC_XWORD(move->m_info));
1912 
1913 				(void) snprintf(index, MAXNDXSIZE,
1914 				    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx));
1915 				dbg_print(0, fmt, index,
1916 				    EC_XWORD(move->m_poffset),
1917 				    ELF_M_SIZE(move->m_info), move->m_repeat,
1918 				    move->m_stride, move->m_value,
1919 				    MSG_INTL(MSG_STR_UNKNOWN));
1920 				continue;
1921 			}
1922 
1923 			symname = relsymname(cache, _cache, strsec,
1924 			    symndx, symnum, ndx, syms, section, BUFSIZ, file,
1925 			    flags);
1926 			sym = (Sym *)(syms + symndx);
1927 
1928 			/*
1929 			 * Additional sanity check.
1930 			 */
1931 			shndx = sym->st_shndx;
1932 			if (!((shndx == SHN_COMMON) ||
1933 			    (((shndx >= 1) && (shndx <= shnum)) &&
1934 			    (cache[shndx].c_shdr)->sh_type == SHT_NOBITS))) {
1935 				(void) fprintf(stderr,
1936 				    MSG_INTL(MSG_ERR_BADSYM2), file,
1937 				    _cache->c_name, demangle(symname, flags));
1938 			}
1939 
1940 			(void) snprintf(index, MAXNDXSIZE,
1941 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(symndx));
1942 			dbg_print(0, fmt, index, EC_XWORD(move->m_poffset),
1943 			    ELF_M_SIZE(move->m_info), move->m_repeat,
1944 			    move->m_stride, move->m_value,
1945 			    demangle(symname, flags));
1946 		}
1947 	}
1948 }
1949 
1950 /*
1951  * Traverse a note section analyzing each note information block.
1952  * The data buffers size is used to validate references before they are made,
1953  * and is decremented as each element is processed.
1954  */
1955 void
1956 note_entry(Cache *cache, Word *data, size_t size, const char *file)
1957 {
1958 	size_t	bsize = size;
1959 
1960 	/*
1961 	 * Print out a single `note' information block.
1962 	 */
1963 	while (size > 0) {
1964 		size_t	namesz, descsz, type, pad, noteoff;
1965 
1966 		noteoff = bsize - size;
1967 		/*
1968 		 * Make sure we can at least reference the 3 initial entries
1969 		 * (4-byte words) of the note information block.
1970 		 */
1971 		if (size >= (sizeof (Word) * 3))
1972 			size -= (sizeof (Word) * 3);
1973 		else {
1974 			(void) fprintf(stderr, MSG_INTL(MSG_NOTE_BADDATASZ),
1975 			    file, cache->c_name, EC_WORD(noteoff));
1976 			return;
1977 		}
1978 
1979 		/*
1980 		 * Make sure any specified name string can be referenced.
1981 		 */
1982 		if ((namesz = *data++) != 0) {
1983 			if (size >= namesz)
1984 				size -= namesz;
1985 			else {
1986 				(void) fprintf(stderr,
1987 				    MSG_INTL(MSG_NOTE_BADNMSZ), file,
1988 				    cache->c_name, EC_WORD(noteoff),
1989 				    EC_WORD(namesz));
1990 				return;
1991 			}
1992 		}
1993 
1994 		/*
1995 		 * Make sure any specified descriptor can be referenced.
1996 		 */
1997 		if ((descsz = *data++) != 0) {
1998 			/*
1999 			 * If namesz isn't a 4-byte multiple, account for any
2000 			 * padding that must exist before the descriptor.
2001 			 */
2002 			if ((pad = (namesz & (sizeof (Word) - 1))) != 0) {
2003 				pad = sizeof (Word) - pad;
2004 				size -= pad;
2005 			}
2006 			if (size >= descsz)
2007 				size -= descsz;
2008 			else {
2009 				(void) fprintf(stderr,
2010 				    MSG_INTL(MSG_NOTE_BADDESZ), file,
2011 				    cache->c_name, EC_WORD(noteoff),
2012 				    EC_WORD(namesz));
2013 				return;
2014 			}
2015 		}
2016 
2017 		type = *data++;
2018 
2019 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2020 		dbg_print(0, MSG_ORIG(MSG_NOTE_TYPE), EC_WORD(type));
2021 
2022 		dbg_print(0, MSG_ORIG(MSG_NOTE_NAMESZ), EC_WORD(namesz));
2023 		if (namesz) {
2024 			char	*name = (char *)data;
2025 
2026 			/*
2027 			 * Since the name string may have 'null' bytes
2028 			 * in it (ia32 .string) - we just write the
2029 			 * whole stream in a single fwrite.
2030 			 */
2031 			(void) fwrite(name, namesz, 1, stdout);
2032 			name = name + ((namesz + (sizeof (Word) - 1)) &
2033 			    ~(sizeof (Word) - 1));
2034 			/* LINTED */
2035 			data = (Word *)name;
2036 			dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2037 		}
2038 
2039 		/*
2040 		 * If multiple information blocks exist within a .note section
2041 		 * account for any padding that must exist before the next
2042 		 * information block.
2043 		 */
2044 		if ((pad = (descsz & (sizeof (Word) - 1))) != 0) {
2045 			pad = sizeof (Word) - pad;
2046 			if (size > pad)
2047 				size -= pad;
2048 		}
2049 
2050 		dbg_print(0, MSG_ORIG(MSG_NOTE_DESCSZ), EC_WORD(descsz));
2051 		if (descsz) {
2052 			int		ndx, byte, word;
2053 			char		string[58], *str = string;
2054 			uchar_t		*desc = (uchar_t *)data;
2055 
2056 			/*
2057 			 * Dump descriptor bytes.
2058 			 */
2059 			for (ndx = byte = word = 0; descsz; descsz--, desc++) {
2060 				int	tok = *desc;
2061 
2062 				(void) snprintf(str, 58, MSG_ORIG(MSG_NOTE_TOK),
2063 				    tok);
2064 				str += 3;
2065 
2066 				if (++byte == 4) {
2067 					*str++ = ' ', *str++ = ' ';
2068 					word++;
2069 					byte = 0;
2070 				}
2071 				if (word == 4) {
2072 					*str = '\0';
2073 					dbg_print(0, MSG_ORIG(MSG_NOTE_DESC),
2074 					    ndx, string);
2075 					word = 0;
2076 					ndx += 16;
2077 					str = string;
2078 				}
2079 			}
2080 			if (byte || word) {
2081 				*str = '\0';
2082 				dbg_print(0, MSG_ORIG(MSG_NOTE_DESC),
2083 				    ndx, string);
2084 			}
2085 
2086 			desc += pad;
2087 			/* LINTED */
2088 			data = (Word *)desc;
2089 		}
2090 	}
2091 }
2092 
2093 /*
2094  * Search for and process a .note section.
2095  */
2096 static void
2097 note(Cache *cache, Word shnum, const char *name, const char *file)
2098 {
2099 	Word	cnt;
2100 
2101 	/*
2102 	 * Otherwise look for any .note sections.
2103 	 */
2104 	for (cnt = 1; cnt < shnum; cnt++) {
2105 		Cache	*_cache = &cache[cnt];
2106 		Shdr	*shdr = _cache->c_shdr;
2107 
2108 		if (shdr->sh_type != SHT_NOTE)
2109 			continue;
2110 		if (name && strcmp(name, _cache->c_name))
2111 			continue;
2112 
2113 		/*
2114 		 * As these sections are often hand rolled, make sure they're
2115 		 * properly aligned before proceeding.
2116 		 */
2117 		if (shdr->sh_offset & (sizeof (Word) - 1)) {
2118 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADALIGN),
2119 			    file, _cache->c_name);
2120 			continue;
2121 		}
2122 		if (_cache->c_data == NULL)
2123 			continue;
2124 
2125 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2126 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_NOTE), _cache->c_name);
2127 		note_entry(_cache, (Word *)_cache->c_data->d_buf,
2128 		/* LINTED */
2129 		    (Word)_cache->c_data->d_size, file);
2130 	}
2131 }
2132 
2133 /*
2134  * Determine an individual hash entry.  This may be the initial hash entry,
2135  * or an associated chain entry.
2136  */
2137 static void
2138 hash_entry(Cache *refsec, Cache *strsec, const char *hsecname, Word hashndx,
2139     Word symndx, Word symn, Sym *syms, const char *file, ulong_t bkts,
2140     uint_t flags, int chain)
2141 {
2142 	Sym		*sym;
2143 	const char	*symname, *str;
2144 	char		_bucket[MAXNDXSIZE], _symndx[MAXNDXSIZE];
2145 	ulong_t		nbkt, nhash;
2146 
2147 	if (symndx > symn) {
2148 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_HSBADSYMNDX), file,
2149 		    EC_WORD(symndx), EC_WORD(hashndx));
2150 		symname = MSG_INTL(MSG_STR_UNKNOWN);
2151 	} else {
2152 		sym = (Sym *)(syms + symndx);
2153 		symname = string(refsec, symndx, strsec, file, sym->st_name);
2154 	}
2155 
2156 	if (chain == 0) {
2157 		(void) snprintf(_bucket, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
2158 		    hashndx);
2159 		str = (const char *)_bucket;
2160 	} else
2161 		str = MSG_ORIG(MSG_STR_EMPTY);
2162 
2163 	(void) snprintf(_symndx, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INDEX2),
2164 	    EC_WORD(symndx));
2165 	dbg_print(0, MSG_ORIG(MSG_FMT_HASH_INFO), str, _symndx,
2166 	    demangle(symname, flags));
2167 
2168 	/*
2169 	 * Determine if this string is in the correct bucket.
2170 	 */
2171 	nhash = elf_hash(symname);
2172 	nbkt = nhash % bkts;
2173 
2174 	if (nbkt != hashndx) {
2175 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADHASH), file,
2176 		    hsecname, symname, EC_WORD(hashndx), nbkt);
2177 	}
2178 }
2179 
2180 #define	MAXCOUNT	500
2181 
2182 static void
2183 hash(Cache *cache, Word shnum, const char *name, const char *file, uint_t flags)
2184 {
2185 	static int	count[MAXCOUNT];
2186 	Word		cnt;
2187 	ulong_t		ndx, bkts;
2188 	char		number[MAXNDXSIZE];
2189 
2190 	for (cnt = 1; cnt < shnum; cnt++) {
2191 		uint_t		*hash, *chain;
2192 		Cache		*_cache = &cache[cnt];
2193 		Shdr		*sshdr, *hshdr = _cache->c_shdr;
2194 		char		*ssecname, *hsecname = _cache->c_name;
2195 		Sym		*syms;
2196 		Word		symn;
2197 
2198 		if (hshdr->sh_type != SHT_HASH)
2199 			continue;
2200 		if (name && strcmp(name, hsecname))
2201 			continue;
2202 
2203 		/*
2204 		 * Determine the hash table data and size.
2205 		 */
2206 		if ((hshdr->sh_entsize == 0) || (hshdr->sh_size == 0)) {
2207 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2208 			    file, hsecname);
2209 			continue;
2210 		}
2211 		if (_cache->c_data == NULL)
2212 			continue;
2213 
2214 		hash = (uint_t *)_cache->c_data->d_buf;
2215 		bkts = *hash;
2216 		chain = hash + 2 + bkts;
2217 		hash += 2;
2218 
2219 		/*
2220 		 * Get the data buffer for the associated symbol table.
2221 		 */
2222 		if ((hshdr->sh_link == 0) || (hshdr->sh_link >= shnum)) {
2223 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2224 			    file, hsecname, EC_WORD(hshdr->sh_link));
2225 			continue;
2226 		}
2227 
2228 		_cache = &cache[hshdr->sh_link];
2229 		ssecname = _cache->c_name;
2230 
2231 		if (_cache->c_data == NULL)
2232 			continue;
2233 
2234 		if ((syms = (Sym *)_cache->c_data->d_buf) == NULL) {
2235 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2236 			    file, ssecname);
2237 			continue;
2238 		}
2239 
2240 		sshdr = _cache->c_shdr;
2241 		/* LINTED */
2242 		symn = (Word)(sshdr->sh_size / sshdr->sh_entsize);
2243 
2244 		/*
2245 		 * Get the associated string table section.
2246 		 */
2247 		if ((sshdr->sh_link == 0) || (sshdr->sh_link >= shnum)) {
2248 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHLINK),
2249 			    file, ssecname, EC_WORD(sshdr->sh_link));
2250 			continue;
2251 		}
2252 
2253 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2254 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_HASH), hsecname);
2255 		dbg_print(0, MSG_INTL(MSG_ELF_HASH_INFO));
2256 
2257 		/*
2258 		 * Loop through the hash buckets, printing the appropriate
2259 		 * symbols.
2260 		 */
2261 		for (ndx = 0; ndx < bkts; ndx++, hash++) {
2262 			Word	_ndx, _cnt;
2263 
2264 			if (*hash == 0) {
2265 				count[0]++;
2266 				continue;
2267 			}
2268 
2269 			hash_entry(_cache, &cache[sshdr->sh_link], hsecname,
2270 			    ndx, *hash, symn, syms, file, bkts, flags, 0);
2271 
2272 			/*
2273 			 * Determine if any other symbols are chained to this
2274 			 * bucket.
2275 			 */
2276 			_ndx = chain[*hash];
2277 			_cnt = 1;
2278 			while (_ndx) {
2279 				hash_entry(_cache, &cache[sshdr->sh_link],
2280 				    hsecname, ndx, _ndx, symn, syms, file,
2281 				    bkts, flags, 1);
2282 				_ndx = chain[_ndx];
2283 				_cnt++;
2284 			}
2285 
2286 			if (_cnt >= MAXCOUNT) {
2287 				(void) fprintf(stderr,
2288 				    MSG_INTL(MSG_HASH_OVERFLW), file,
2289 				    _cache->c_name, EC_WORD(ndx),
2290 				    EC_WORD(_cnt));
2291 			} else
2292 				count[_cnt]++;
2293 		}
2294 		break;
2295 	}
2296 
2297 	/*
2298 	 * Print out the count information.
2299 	 */
2300 	bkts = cnt = 0;
2301 	dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2302 
2303 	for (ndx = 0; ndx < MAXCOUNT; ndx++) {
2304 		Word	_cnt;
2305 
2306 		if ((_cnt = count[ndx]) == 0)
2307 			continue;
2308 
2309 		(void) snprintf(number, MAXNDXSIZE,
2310 		    MSG_ORIG(MSG_FMT_INTEGER), _cnt);
2311 		dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS1), number,
2312 		    EC_WORD(ndx));
2313 		bkts += _cnt;
2314 		cnt += (Word)(ndx * _cnt);
2315 	}
2316 	if (cnt) {
2317 		(void) snprintf(number, MAXNDXSIZE, MSG_ORIG(MSG_FMT_INTEGER),
2318 		    bkts);
2319 		dbg_print(0, MSG_INTL(MSG_ELF_HASH_BKTS2), number,
2320 		    EC_WORD(cnt));
2321 	}
2322 }
2323 
2324 static void
2325 group(Cache *cache, Word shnum, const char *name, const char *file,
2326     uint_t flags)
2327 {
2328 	Word	scnt;
2329 
2330 	for (scnt = 1; scnt < shnum; scnt++) {
2331 		Cache	*_cache = &cache[scnt];
2332 		Shdr	*shdr = _cache->c_shdr;
2333 		Word	*grpdata, gcnt, grpcnt, symnum, unknown;
2334 		Cache	*symsec, *strsec;
2335 		Sym	*syms, *sym;
2336 		char	flgstrbuf[MSG_GRP_COMDAT_SIZE + 10];
2337 
2338 		if (shdr->sh_type != SHT_GROUP)
2339 			continue;
2340 		if (name && strcmp(name, _cache->c_name))
2341 			continue;
2342 		if ((_cache->c_data == NULL) ||
2343 		    ((grpdata = (Word *)_cache->c_data->d_buf) == NULL))
2344 			continue;
2345 		grpcnt = shdr->sh_size / sizeof (Word);
2346 
2347 		/*
2348 		 * Get the data buffer for the associated symbol table and
2349 		 * string table.
2350 		 */
2351 		if (stringtbl(cache, 1, scnt, shnum, file,
2352 		    &symnum, &symsec, &strsec) == 0)
2353 			return;
2354 
2355 		syms = symsec->c_data->d_buf;
2356 
2357 		dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2358 		dbg_print(0, MSG_INTL(MSG_ELF_SCN_GRP), _cache->c_name);
2359 		dbg_print(0, MSG_INTL(MSG_GRP_TITLE));
2360 
2361 		/*
2362 		 * The first element of the group defines the group.  The
2363 		 * associated symbol is defined by the sh_link field.
2364 		 */
2365 		if ((shdr->sh_info == SHN_UNDEF) || (shdr->sh_info > symnum)) {
2366 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSHINFO),
2367 			    file, _cache->c_name, EC_WORD(shdr->sh_info));
2368 			return;
2369 		}
2370 
2371 		(void) strcpy(flgstrbuf, MSG_ORIG(MSG_STR_OSQBRKT));
2372 		if (grpdata[0] & GRP_COMDAT) {
2373 			(void) strcat(flgstrbuf, MSG_ORIG(MSG_GRP_COMDAT));
2374 		}
2375 		if ((unknown = (grpdata[0] & ~GRP_COMDAT)) != 0) {
2376 			size_t	len = strlen(flgstrbuf);
2377 
2378 			(void) snprintf(&flgstrbuf[len],
2379 			    (MSG_GRP_COMDAT_SIZE + 10 - len),
2380 			    MSG_ORIG(MSG_GRP_UNKNOWN), unknown);
2381 		}
2382 		(void) strcat(flgstrbuf, MSG_ORIG(MSG_STR_CSQBRKT));
2383 		sym = (Sym *)(syms + shdr->sh_info);
2384 
2385 		dbg_print(0, MSG_INTL(MSG_GRP_SIGNATURE), flgstrbuf,
2386 		    demangle(string(_cache, 0, strsec, file, sym->st_name),
2387 		    flags));
2388 
2389 		for (gcnt = 1; gcnt < grpcnt; gcnt++) {
2390 			char		index[MAXNDXSIZE];
2391 			const char	*name;
2392 
2393 			(void) snprintf(index, MAXNDXSIZE,
2394 			    MSG_ORIG(MSG_FMT_INDEX), EC_XWORD(gcnt));
2395 
2396 			if (grpdata[gcnt] >= shnum)
2397 				name = MSG_INTL(MSG_GRP_INVALSCN);
2398 			else
2399 				name = cache[grpdata[gcnt]].c_name;
2400 
2401 			(void) printf(MSG_ORIG(MSG_GRP_ENTRY), index, name,
2402 				EC_XWORD(grpdata[gcnt]));
2403 		}
2404 	}
2405 }
2406 
2407 static void
2408 got(Cache *cache, Word shnum, Ehdr *ehdr, const char *file, uint_t flags)
2409 {
2410 	Cache		*gotcache = 0, *symtab = 0, *_cache;
2411 	Addr		gotbgn, gotend;
2412 	Shdr		*gotshdr;
2413 	Word		cnt, gotents, gotndx;
2414 	size_t		gentsize;
2415 	Got_info	*gottable;
2416 	char		*gotdata;
2417 	Sym		*gotsym;
2418 	Xword		gotsymaddr;
2419 
2420 	/*
2421 	 * First, find the got.
2422 	 */
2423 	for (cnt = 1; cnt < shnum; cnt++) {
2424 		_cache = &cache[cnt];
2425 		if (strncmp(_cache->c_name, MSG_ORIG(MSG_ELF_GOT),
2426 		    MSG_ELF_GOT_SIZE) == 0) {
2427 			gotcache = _cache;
2428 			break;
2429 		}
2430 	}
2431 	if (gotcache == 0)
2432 		return;
2433 
2434 	/*
2435 	 * A got section within a relocatable object is suspicious.
2436 	 */
2437 	if (ehdr->e_type == ET_REL) {
2438 		(void) fprintf(stderr, MSG_INTL(MSG_GOT_UNEXPECTED), file,
2439 		    _cache->c_name);
2440 	}
2441 
2442 	gotshdr = gotcache->c_shdr;
2443 	if (gotshdr->sh_size == 0) {
2444 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2445 		    file, gotcache->c_name);
2446 		return;
2447 	}
2448 
2449 	gotbgn = gotshdr->sh_addr;
2450 	gotend = gotbgn + gotshdr->sh_size;
2451 
2452 	/*
2453 	 * Some architectures don't properly set the sh_entsize for the GOT
2454 	 * table.  If it's not set, default to a size of a pointer.
2455 	 */
2456 	if ((gentsize = gotshdr->sh_entsize) == 0)
2457 		gentsize = sizeof (Xword);
2458 
2459 	if (gotcache->c_data == NULL)
2460 		return;
2461 
2462 	/* LINTED */
2463 	gotents = (Word)(gotshdr->sh_size / gentsize);
2464 	gotdata = gotcache->c_data->d_buf;
2465 
2466 	if ((gottable = calloc(gotents, sizeof (Got_info))) == 0) {
2467 		int err = errno;
2468 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC), file,
2469 		    strerror(err));
2470 		return;
2471 	}
2472 
2473 	/*
2474 	 * Now we scan through all the sections looking for any relocations
2475 	 * that may be against the GOT.  Since these may not be isolated to a
2476 	 * .rel[a].got section we check them all.
2477 	 * While scanning sections save the symbol table entry (a symtab
2478 	 * overriding a dynsym) so that we can lookup _GLOBAL_OFFSET_TABLE_.
2479 	 */
2480 	for (cnt = 1; cnt < shnum; cnt++) {
2481 		Word		type, symnum;
2482 		Xword		relndx, relnum, relsize;
2483 		void		*rels;
2484 		Sym		*syms;
2485 		Cache		*symsec, *strsec;
2486 		Cache		*_cache = &cache[cnt];
2487 		Shdr		*shdr;
2488 
2489 		shdr = _cache->c_shdr;
2490 		type = shdr->sh_type;
2491 
2492 		if ((symtab == 0) && (type == SHT_DYNSYM)) {
2493 			symtab = _cache;
2494 			continue;
2495 		}
2496 		if (type == SHT_SYMTAB) {
2497 			symtab = _cache;
2498 			continue;
2499 		}
2500 		if ((type != SHT_RELA) && (type != SHT_REL))
2501 			continue;
2502 
2503 		/*
2504 		 * Decide entry size.
2505 		 */
2506 		if (((relsize = shdr->sh_entsize) == 0) ||
2507 		    (relsize > shdr->sh_size)) {
2508 			if (type == SHT_RELA)
2509 				relsize = sizeof (Rela);
2510 			else
2511 				relsize = sizeof (Rel);
2512 		}
2513 
2514 		/*
2515 		 * Determine the number of relocations available.
2516 		 */
2517 		if (shdr->sh_size == 0) {
2518 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_BADSZ),
2519 			    file, _cache->c_name);
2520 			continue;
2521 		}
2522 		if (_cache->c_data == NULL)
2523 			continue;
2524 
2525 		rels = _cache->c_data->d_buf;
2526 		relnum = shdr->sh_size / relsize;
2527 
2528 		/*
2529 		 * Get the data buffer for the associated symbol table and
2530 		 * string table.
2531 		 */
2532 		if (stringtbl(cache, 1, cnt, shnum, file,
2533 		    &symnum, &symsec, &strsec) == 0)
2534 			continue;
2535 
2536 		syms = symsec->c_data->d_buf;
2537 
2538 		/*
2539 		 * Loop through the relocation entries.
2540 		 */
2541 		for (relndx = 0; relndx < relnum; relndx++,
2542 		    rels = (void *)((char *)rels + relsize)) {
2543 			char		section[BUFSIZ];
2544 			Addr		offset;
2545 			Got_info	*gip;
2546 			Word		symndx, reltype;
2547 			Rela		*rela;
2548 			Rel		*rel;
2549 
2550 			/*
2551 			 * Unravel the relocation.
2552 			 */
2553 			if (type == SHT_RELA) {
2554 				rela = (Rela *)rels;
2555 				symndx = ELF_R_SYM(rela->r_info);
2556 				reltype = ELF_R_TYPE(rela->r_info);
2557 				offset = rela->r_offset;
2558 			} else {
2559 				rel = (Rel *)rels;
2560 				symndx = ELF_R_SYM(rel->r_info);
2561 				reltype = ELF_R_TYPE(rel->r_info);
2562 				offset = rel->r_offset;
2563 			}
2564 
2565 			/*
2566 			 * Only pay attention to relocations against the GOT.
2567 			 */
2568 			if ((offset < gotbgn) || (offset > gotend))
2569 				continue;
2570 
2571 			/* LINTED */
2572 			gotndx = (Word)((offset - gotbgn) /
2573 			    gotshdr->sh_entsize);
2574 			gip = &gottable[gotndx];
2575 
2576 			if (gip->g_reltype != 0) {
2577 				(void) fprintf(stderr,
2578 				    MSG_INTL(MSG_GOT_MULTIPLE), file,
2579 				    EC_WORD(gotndx), EC_ADDR(offset));
2580 				continue;
2581 			}
2582 
2583 			if (symndx)
2584 				gip->g_symname = relsymname(cache, _cache,
2585 				    strsec, symndx, symnum, relndx, syms,
2586 				    section, BUFSIZ, file, flags);
2587 			gip->g_reltype = reltype;
2588 			gip->g_rel = rels;
2589 		}
2590 	}
2591 
2592 	if (symlookup(MSG_ORIG(MSG_GOT_SYM), cache, shnum, &gotsym, symtab,
2593 	    file))
2594 		gotsymaddr = gotsym->st_value;
2595 	else
2596 		gotsymaddr = gotbgn;
2597 
2598 	dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2599 	dbg_print(0, MSG_INTL(MSG_ELF_SCN_GOT), gotcache->c_name);
2600 	Elf_got_title(0);
2601 
2602 	for (gotndx = 0; gotndx < gotents; gotndx++) {
2603 		Got_info	*gip;
2604 		Sword		gindex;
2605 		Addr		gaddr;
2606 		Xword		gotentry;
2607 
2608 		gip = &gottable[gotndx];
2609 
2610 		gaddr = gotbgn + (gotndx * gentsize);
2611 		gindex = (Sword)(gaddr - gotsymaddr) / (Sword)gentsize;
2612 
2613 		if (gentsize == sizeof (Word))
2614 			/* LINTED */
2615 			gotentry = (Xword)(*((Word *)(gotdata) + gotndx));
2616 		else
2617 			/* LINTED */
2618 			gotentry = *((Xword *)(gotdata) + gotndx);
2619 
2620 		Elf_got_entry(0, gindex, gaddr, gotentry, ehdr->e_machine,
2621 		    gip->g_reltype, gip->g_rel, gip->g_symname);
2622 	}
2623 	free(gottable);
2624 }
2625 
2626 void
2627 checksum(Elf *elf)
2628 {
2629 	dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2630 	dbg_print(0, MSG_INTL(MSG_STR_CHECKSUM), elf_checksum(elf));
2631 }
2632 
2633 void
2634 regular(const char *file, Elf *elf, uint_t flags, char *Nname, int wfd)
2635 {
2636 	/*
2637 	 * Program header names that we can test for.
2638 	 */
2639 	static const char *pnames[PT_NUM] = {
2640 		MSG_ORIG(MSG_PT_NULL),		MSG_ORIG(MSG_PT_LOAD),
2641 		MSG_ORIG(MSG_PT_DYNAMIC),	MSG_ORIG(MSG_PT_INTERP),
2642 		MSG_ORIG(MSG_PT_NOTE),		MSG_ORIG(MSG_PT_SHLIB),
2643 		MSG_ORIG(MSG_PT_PHDR),		MSG_ORIG(MSG_PT_TLS)
2644 	};
2645 #if PT_NUM != (PT_TLS + 1)
2646 #error "P_NUM has grown. Update addr_symtype[]"
2647 #endif
2648 
2649 	Elf_Scn		*scn;
2650 	Ehdr		*ehdr;
2651 	Elf_Data	*data;
2652 	size_t		cnt, shstrndx, shnum, phnum;
2653 	Shdr		*nameshdr, *shdr;
2654 	char		*names = 0;
2655 	Cache		*cache, *_cache;
2656 	VERSYM_STATE	versym;
2657 
2658 	if ((ehdr = elf_getehdr(elf)) == NULL) {
2659 		failure(file, MSG_ORIG(MSG_ELF_GETEHDR));
2660 		return;
2661 	}
2662 
2663 	if (elf_getshnum(elf, &shnum) == 0) {
2664 		failure(file, MSG_ORIG(MSG_ELF_GETSHNUM));
2665 		return;
2666 	}
2667 
2668 	if (elf_getshstrndx(elf, &shstrndx) == 0) {
2669 		failure(file, MSG_ORIG(MSG_ELF_GETSHSTRNDX));
2670 		return;
2671 	}
2672 
2673 	if (elf_getphnum(elf, &phnum) == 0) {
2674 		failure(file, MSG_ORIG(MSG_ELF_GETPHNUM));
2675 		return;
2676 	}
2677 
2678 	if ((scn = elf_getscn(elf, 0)) != NULL) {
2679 		if ((shdr = elf_getshdr(scn)) == NULL) {
2680 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
2681 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN), 0);
2682 			return;
2683 		}
2684 	} else
2685 		shdr = 0;
2686 
2687 	/*
2688 	 * Print the elf header.
2689 	 */
2690 	if (flags & FLG_EHDR)
2691 		Elf_ehdr(0, ehdr, shdr);
2692 
2693 	/*
2694 	 * Print the program headers.
2695 	 */
2696 	if ((flags & FLG_PHDR) && (phnum != 0)) {
2697 		Phdr *phdr;
2698 
2699 		if ((phdr = elf_getphdr(elf)) == NULL) {
2700 			failure(file, MSG_ORIG(MSG_ELF_GETPHDR));
2701 			return;
2702 		}
2703 
2704 		for (cnt = 0; cnt < phnum; phdr++, cnt++) {
2705 
2706 			if (Nname && ((phdr->p_type >= PT_NUM) ||
2707 			    (strcmp(Nname, pnames[phdr->p_type]) != 0)))
2708 				continue;
2709 
2710 			dbg_print(0, MSG_ORIG(MSG_STR_EMPTY));
2711 			dbg_print(0, MSG_INTL(MSG_ELF_PHDR), EC_WORD(cnt));
2712 			Elf_phdr(0, ehdr->e_machine, phdr);
2713 		}
2714 	}
2715 
2716 	/*
2717 	 * Return now if there are no section, if there's just one section to
2718 	 * act as an extension of the ELF header, or if on section information
2719 	 * was requested.
2720 	 */
2721 	if ((shnum <= 1) || (flags && (flags & ~(FLG_EHDR | FLG_PHDR)) == 0)) {
2722 		if ((ehdr->e_type == ET_CORE) && (flags & FLG_NOTE))
2723 			note(0, shnum, 0, file);
2724 		return;
2725 	}
2726 
2727 	/*
2728 	 * Obtain the .shstrtab data buffer to provide the required section
2729 	 * name strings.
2730 	 */
2731 	if ((scn = elf_getscn(elf, shstrndx)) == NULL) {
2732 		failure(file, MSG_ORIG(MSG_ELF_GETSCN));
2733 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SHDR),
2734 		    EC_XWORD(shstrndx));
2735 
2736 	} else if ((data = elf_getdata(scn, NULL)) == NULL) {
2737 		failure(file, MSG_ORIG(MSG_ELF_GETDATA));
2738 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_DATA),
2739 		    EC_XWORD(shstrndx));
2740 
2741 	} else if ((nameshdr = elf_getshdr(scn)) == NULL) {
2742 		failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
2743 		(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
2744 		    EC_WORD(elf_ndxscn(scn)));
2745 
2746 	} else if ((names = data->d_buf) == 0)
2747 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_SHSTRNULL), file);
2748 
2749 	/*
2750 	 * Allocate a cache to maintain a descriptor for each section.
2751 	 */
2752 	if ((cache = malloc(shnum * sizeof (Cache))) == 0) {
2753 		int err = errno;
2754 		(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
2755 		    file, strerror(err));
2756 		return;
2757 	}
2758 
2759 	*cache = cache_init;
2760 	_cache = cache;
2761 	_cache++;
2762 
2763 	/*
2764 	 * Traverse the sections of the file.  This gathering of data is
2765 	 * carried out in two passes.  First, the section headers are captured
2766 	 * and the section header names are evaluated.  A verification pass is
2767 	 * then carried out over the section information.  Files have been
2768 	 * known to exhibit overlapping (and hence erroneous) section header
2769 	 * information.
2770 	 *
2771 	 * Finally, the data for each section is obtained.  This processing is
2772 	 * carried out after section verification because should any section
2773 	 * header overlap occur, and a file needs translating (ie. xlate'ing
2774 	 * information from a non-native architecture file), then the process
2775 	 * of translation can corrupt the section header information.  Of
2776 	 * course, if there is any section overlap, the data related to the
2777 	 * sections is going to be compromised.  However, it is the translation
2778 	 * of this data that has caused problems with elfdump()'s ability to
2779 	 * extract the data.
2780 	 */
2781 	for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn);
2782 	    cnt++, _cache++) {
2783 		char	scnndxnm[100];
2784 
2785 		_cache->c_scn = scn;
2786 
2787 		if ((_cache->c_shdr = elf_getshdr(scn)) == NULL) {
2788 			failure(file, MSG_ORIG(MSG_ELF_GETSHDR));
2789 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCN),
2790 			    EC_WORD(elf_ndxscn(scn)));
2791 		}
2792 
2793 		/*
2794 		 * If a shstrtab exists, assign the section name.
2795 		 */
2796 		if (names && _cache->c_shdr) {
2797 			if (_cache->c_shdr->sh_name &&
2798 			    /* LINTED */
2799 			    (nameshdr->sh_size > _cache->c_shdr->sh_name)) {
2800 				_cache->c_name =
2801 				    names + _cache->c_shdr->sh_name;
2802 				continue;
2803 			}
2804 
2805 			/*
2806 			 * Generate an error if the section name index is zero
2807 			 * or exceeds the shstrtab data.  Fall through to
2808 			 * fabricate a section name.
2809 			 */
2810 			if ((_cache->c_shdr->sh_name == 0) ||
2811 			    /* LINTED */
2812 			    (nameshdr->sh_size <= _cache->c_shdr->sh_name)) {
2813 				(void) fprintf(stderr,
2814 				    MSG_INTL(MSG_ERR_BADSHNAME), file,
2815 				    EC_WORD(cnt),
2816 				    EC_XWORD(_cache->c_shdr->sh_name));
2817 			}
2818 		}
2819 
2820 		/*
2821 		 * If there exists no shstrtab data, or a section header has no
2822 		 * name (an invalid index of 0), then compose a name for the
2823 		 * section.
2824 		 */
2825 		(void) snprintf(scnndxnm, sizeof (scnndxnm),
2826 		    MSG_INTL(MSG_FMT_SCNNDX), cnt);
2827 
2828 		if ((_cache->c_name = malloc(strlen(scnndxnm) + 1)) == 0) {
2829 			int err = errno;
2830 			(void) fprintf(stderr, MSG_INTL(MSG_ERR_MALLOC),
2831 			    file, strerror(err));
2832 			return;
2833 		}
2834 		(void) strcpy(_cache->c_name, scnndxnm);
2835 	}
2836 
2837 	/*
2838 	 * Having collected all the sections, validate their address range.
2839 	 * Cases have existed where the section information has been invalid.
2840 	 * This can lead to all sorts of other, hard to diagnose errors, as
2841 	 * each section is processed individually (ie. with elf_getdata()).
2842 	 * Here, we carry out some address comparisons to catch a family of
2843 	 * overlapping memory issues we have observed (likely, there are others
2844 	 * that we have yet to discover).
2845 	 *
2846 	 * Note, should any memory overlap occur, obtaining any additional
2847 	 * data from the file is questionable.  However, it might still be
2848 	 * possible to inspect the ELF header, Programs headers, or individual
2849 	 * sections, so rather than bailing on an error condition, continue
2850 	 * processing to see if any data can be salvaged.
2851 	 */
2852 	for (cnt = 1; cnt < shnum; cnt++) {
2853 		Cache	*_cache = &cache[cnt];
2854 		Shdr	*shdr = _cache->c_shdr;
2855 		Off	bgn1, bgn = shdr->sh_offset;
2856 		Off	end1, end = shdr->sh_offset + shdr->sh_size;
2857 		int	cnt1;
2858 
2859 		if ((shdr->sh_size == 0) || (shdr->sh_type == SHT_NOBITS))
2860 			continue;
2861 
2862 		for (cnt1 = 1; cnt1 < shnum; cnt1++) {
2863 			Cache	*_cache1 = &cache[cnt1];
2864 			Shdr	*shdr1 = _cache1->c_shdr;
2865 
2866 			bgn1 = shdr1->sh_offset;
2867 			end1 = shdr1->sh_offset + shdr1->sh_size;
2868 
2869 			if ((cnt1 == cnt) || (shdr->sh_size == 0) ||
2870 			    (shdr1->sh_type == SHT_NOBITS))
2871 				continue;
2872 
2873 			if (((bgn1 <= bgn) && (end1 > bgn)) ||
2874 			    ((bgn1 < end) && (end1 >= end))) {
2875 				(void) fprintf(stderr,
2876 				    MSG_INTL(MSG_ERR_SECMEMOVER), file,
2877 				    EC_WORD(elf_ndxscn(_cache1->c_scn)),
2878 				    _cache1->c_name, EC_OFF(bgn1), EC_OFF(end1),
2879 				    EC_WORD(elf_ndxscn(_cache->c_scn)),
2880 				    _cache->c_name, EC_OFF(bgn), EC_OFF(end));
2881 			}
2882 		}
2883 
2884 		/*
2885 		 * And finally, make sure this section doesn't overlap the
2886 		 * section header itself.
2887 		 */
2888 		bgn1 = ehdr->e_shoff;
2889 		end1 = ehdr->e_shoff + (ehdr->e_shentsize * ehdr->e_shnum);
2890 
2891 		if (((bgn1 <= bgn) && (end1 > bgn)) ||
2892 		    ((bgn1 < end) && (end1 >= end))) {
2893 			(void) fprintf(stderr,
2894 			    MSG_INTL(MSG_ERR_SHDRMEMOVER), file, EC_OFF(bgn1),
2895 			    EC_OFF(end1),
2896 			    EC_WORD(elf_ndxscn(_cache->c_scn)),
2897 			    _cache->c_name, EC_OFF(bgn), EC_OFF(end));
2898 		}
2899 	}
2900 
2901 	/*
2902 	 * Finally, obtain the data for each section.
2903 	 */
2904 	for (cnt = 1; cnt < shnum; cnt++) {
2905 		Cache	*_cache = &cache[cnt];
2906 		Elf_Scn	*scn = _cache->c_scn;
2907 
2908 		if ((_cache->c_data = elf_getdata(scn, NULL)) == NULL) {
2909 			failure(file, MSG_ORIG(MSG_ELF_GETDATA));
2910 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_ERR_SCNDATA),
2911 			    EC_WORD(elf_ndxscn(scn)));
2912 		}
2913 
2914 		/*
2915 		 * Do we wish to write the section out?
2916 		 */
2917 		if (wfd && Nname && (strcmp(Nname, _cache->c_name) == 0) &&
2918 		    _cache->c_data) {
2919 			(void) write(wfd, _cache->c_data->d_buf,
2920 			    _cache->c_data->d_size);
2921 		}
2922 	}
2923 
2924 	if (flags & FLG_SHDR)
2925 		sections(file, cache, shnum, ehdr, Nname);
2926 
2927 	if (flags & FLG_INTERP)
2928 		interp(file, cache, shnum, phnum, elf);
2929 
2930 	versions(cache, shnum, file, flags, &versym);
2931 
2932 	if (flags & FLG_SYMBOLS)
2933 		symbols(cache, shnum, ehdr, Nname, &versym, file, flags);
2934 
2935 	if (flags & FLG_SORT)
2936 		sunw_sort(cache, shnum, ehdr, Nname, &versym, file, flags);
2937 
2938 	if (flags & FLG_HASH)
2939 		hash(cache, shnum, Nname, file, flags);
2940 
2941 	if (flags & FLG_GOT)
2942 		got(cache, shnum, ehdr, file, flags);
2943 
2944 	if (flags & FLG_GROUP)
2945 		group(cache, shnum, Nname, file, flags);
2946 
2947 	if (flags & FLG_SYMINFO)
2948 		syminfo(cache, shnum, file);
2949 
2950 	if (flags & FLG_RELOC)
2951 		reloc(cache, shnum, ehdr, Nname, file, flags);
2952 
2953 	if (flags & FLG_DYNAMIC)
2954 		dynamic(cache, shnum, ehdr, file);
2955 
2956 	if (flags & FLG_NOTE)
2957 		note(cache, shnum, Nname, file);
2958 
2959 	if (flags & FLG_MOVE)
2960 		move(cache, shnum, Nname, file, flags);
2961 
2962 	if (flags & FLG_CHECKSUM)
2963 		checksum(elf);
2964 
2965 	if (flags & FLG_CAP)
2966 		cap(file, cache, shnum, phnum, ehdr, elf);
2967 
2968 	if (flags & FLG_UNWIND)
2969 		unwind(cache, shnum, phnum, ehdr, Nname, file, elf);
2970 
2971 	free(cache);
2972 }
2973