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