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