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