xref: /titanic_50/usr/src/cmd/sgs/dump/common/dump.c (revision d8260c5137b0926a897a3763eca8997922ad7401)
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 (c) 1988 AT&T
24  *	  All Rights Reserved
25  *
26  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
27  * Use is subject to license terms.
28  */
29 
30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <locale.h>
35 #include <unistd.h>
36 #include <libelf.h>
37 #include <link.h>
38 #include <sys/elf_M32.h>
39 #include <sys/elf_386.h>
40 #include <sys/elf_SPARC.h>
41 #include <sys/elf_amd64.h>
42 #include <sys/machelf.h>
43 #include <fcntl.h>
44 #include <sys/stat.h>
45 #include <errno.h>
46 #include <string.h>
47 #include "sgs.h"
48 #include "conv.h"
49 #include "dump.h"
50 
51 
52 #define	OPTSTR	"agcd:fhn:oprstvCLT:V?"		/* option string for getopt() */
53 
54 const char *UNKNOWN = "<unknown>";
55 
56 static SCNTAB *p_symtab, *p_head_scns, *p_dynsym;
57 
58 static int
59 	x_flag = 0,	/* option requires section header table */
60 	z_flag = 0,	/* process files within an archive */
61 	rn_flag = 0;	/* dump named relocation information */
62 
63 static int
64 	/* flags: ?_flag corresponds to ? option */
65 	a_flag = 0,	/* dump archive header of each member of archive */
66 	g_flag = 0,	/* dump archive symbol table */
67 	c_flag = 0,	/* dump the string table */
68 	d_flag = 0,	/* dump range of sections */
69 	f_flag = 0,	/* dump each file header */
70 	h_flag = 0,	/* dump section headers */
71 	n_flag = 0,	/* dump named section */
72 	o_flag = 0,	/* dump each program execution header */
73 	r_flag = 0,	/* dump relocation information */
74 	s_flag = 0,	/* dump section contents */
75 	t_flag = 0,	/* dump symbol table entries */
76 	C_flag = 0,	/* dump decoded C++ symbol names */
77 	L_flag = 0,	/* dump dynamic linking information */
78 	T_flag = 0,	/* dump symbol table range */
79 	V_flag = 0;	/* dump version information */
80 
81 int	p_flag = 0,	/* suppress printing of headings */
82 	v_flag = 0;	/* print information in verbose form */
83 
84 static int
85 	d_low = 0,	/* range for use with -d */
86 	d_hi = 0,
87 	d_num = 0;
88 
89 static int
90 	T_low = 0,	/* range for use with -T */
91 	T_hi = 0,
92 	T_num = 0;
93 
94 static char *name = NULL; /* for use with -n option */
95 char *prog_name;
96 static int errflag = 0;
97 
98 static struct stab_list_s {
99 	struct stab_list_s *next;
100 	char *strings;
101 	size_t size;
102 } *StringTableList = (void *)0;
103 
104 extern void ar_sym_read();
105 extern void dump_exec_header();
106 
107 
108 /*
109  * Get the section descriptor and set the size of the
110  * data returned.  Data is byte-order converted.
111  */
112 void *
113 get_scndata(Elf_Scn *fd_scn, size_t *size)
114 {
115 	Elf_Data *p_data;
116 
117 	p_data = 0;
118 	if ((p_data = elf_getdata(fd_scn, p_data)) == 0 ||
119 	    p_data->d_size == 0) {
120 		return (NULL);
121 	}
122 	*size = p_data->d_size;
123 	return (p_data->d_buf);
124 }
125 
126 /*
127  * Get the section descriptor and set the size of the
128  * data returned.  Data is raw (i.e., not byte-order converted).
129  */
130 static void *
131 get_rawscn(Elf_Scn *fd_scn, size_t *size)
132 {
133 	Elf_Data *p_data;
134 
135 	p_data = 0;
136 	if ((p_data = elf_rawdata(fd_scn, p_data)) == 0 ||
137 	    p_data->d_size == 0) {
138 		return (NULL);
139 	}
140 
141 	*size = p_data->d_size;
142 	return (p_data->d_buf);
143 }
144 
145 /*
146  * Print out a usage message in short form when program is invoked
147  * with insufficient or no arguments, and in long form when given
148  * either a ? or an invalid option.
149  */
150 static void
151 usage()
152 {
153 	(void) fprintf(stderr,
154 	"Usage: %s [-%s] file(s) ...\n", prog_name, OPTSTR);
155 	if (errflag) {
156 		(void) fprintf(stderr,
157 		"\t\t[-a dump archive header of each member of archive]\n\
158 		[-g dump archive global symbol table]\n\
159 		[-c dump the string table]\n\
160 		[-d dump range of sections]\n\
161 		[-f dump each file header]\n\
162 		[-h dump section headers]\n\
163 		[-n dump named section]\n\
164 		[-o dump each program execution header]\n\
165 		[-p suppress printing of headings]\n\
166 		[-r dump relocation information]\n\
167 		[-s dump section contents]\n\
168 		[-t dump symbol table entries]\n\
169 		[-v print information in verbose form]\n\
170 		[-C dump decoded C++ symbol names]\n\
171 		[-L dump the .dynamic structure]\n\
172 		[-T dump symbol table range]\n\
173 		[-V dump version information]\n");
174 	}
175 }
176 
177 /*
178  * Set a range.  Input is a character string, a lower
179  * bound and an upper bound.  This function converts
180  * a character string into its correct integer values,
181  * setting the first value as the lower bound, and
182  * the second value as the upper bound.  If more values
183  * are given they are ignored with a warning.
184  */
185 static void
186 set_range(char *s, int  *low, int  *high)
187 {
188 	char *w;
189 	char *lasts;
190 
191 	while ((w = strtok_r(s, ",", &lasts)) != NULL) {
192 		if (!(*low))
193 			/* LINTED */
194 			*low = (int)atol(w);
195 		else
196 			if (!(*high))
197 				/* LINTED */
198 				*high = (int)atol(w);
199 			else {
200 				(void) fprintf(stderr,
201 					"%s: too many arguments - %s ignored\n",
202 					prog_name, w);
203 				return;
204 			}
205 		s = NULL;
206 	} /* end while */
207 }
208 
209 
210 /*
211  * Print static shared library information.
212  */
213 static void
214 print_static(SCNTAB *l_scns, char *filename)
215 {
216 	size_t section_size;
217 	unsigned char *strtab;
218 	unsigned char *path, buf[1024];
219 	unsigned long *temp;
220 	unsigned long total, topath;
221 
222 	(void) printf("\n  **** STATIC SHARED LIBRARY INFORMATION ****\n");
223 	(void) printf("\n%s:\n", filename);
224 	(void) printf("\t");
225 	section_size  = 0;
226 	if ((strtab = (unsigned char *)
227 	    get_scndata(l_scns->p_sd, &section_size)) == NULL) {
228 		return;
229 	}
230 
231 	while (section_size != 0) {
232 		/* LINTED */
233 		temp = (unsigned long *)strtab;
234 		total = temp[0];
235 		topath = temp[1];
236 		path = strtab + (topath*sizeof (long));
237 		(void) strncpy((char *)buf, (char *)path,
238 			(total - topath)*sizeof (long));
239 		(void) fprintf(stdout, "%s\n", buf);
240 		strtab += total*sizeof (long);
241 		section_size -= (total*sizeof (long));
242 	}
243 }
244 
245 /*
246  * Print raw data in hexidecimal.  Input is the section data to
247  * be printed out and the size of the data.  Output is relative
248  * to a table lookup in dumpmap.h.
249  */
250 static void
251 print_rawdata(unsigned char *p_sec, size_t size)
252 {
253 	size_t   j;
254 	size_t   count;
255 
256 	count = 1;
257 
258 	(void) printf("\t");
259 	for (j = size/sizeof (short); j != 0; --j, ++count) {
260 		(void) printf("%.2x %.2x ", p_sec[0], p_sec[1]);
261 		p_sec += 2;
262 		if (count == 12) {
263 			(void) printf("\n\t");
264 			count = 0;
265 		}
266 	}
267 
268 	/*
269 	 * take care of last byte if odd byte section
270 	 */
271 	if ((size & 0x1L) == 1L)
272 		(void) printf("%.2x", *p_sec);
273 	(void) printf("\n");
274 }
275 
276 
277 
278 /*
279  * Print relocation data of type SHT_RELA
280  * If d_flag, print data corresponding only to
281  * the section or range of sections specified.
282  * If n_flag, print data corresponding only to
283  * the named section.
284  */
285 static void
286 print_rela(Elf *elf_file, SCNTAB *p_scns, Elf_Data *rdata, Elf_Data *sym_data,
287 	GElf_Ehdr * p_ehdr, size_t reloc_size, size_t sym_size, char *filename,
288 	SCNTAB *reloc_symtab)
289 {
290 	GElf_Rela rela;
291 	GElf_Sym sym;
292 	size_t no_entries;
293 	size_t rel_entsize;
294 	size_t no_syms;
295 	int type, symid;
296 	static int n_title = 0;
297 	int ndx = 0;
298 	char *sym_name;
299 	int adj = 0;
300 
301 	if (gelf_getclass(elf_file) == ELFCLASS64)
302 		adj = 8;
303 
304 	rel_entsize = p_scns->p_shdr.sh_entsize;
305 	if ((rel_entsize == 0) ||
306 	    (rel_entsize > p_scns->p_shdr.sh_size)) {
307 		rel_entsize = gelf_fsize(elf_file, ELF_T_RELA, 1,
308 		    EV_CURRENT);
309 	}
310 	no_entries = reloc_size / rel_entsize;
311 
312 	no_syms = sym_size / gelf_fsize(elf_file, ELF_T_SYM, 1, EV_CURRENT);
313 	while (no_entries--) {
314 		(void) gelf_getrela(rdata, ndx, &rela);
315 		/* LINTED */
316 		type = (int)GELF_R_TYPE(rela.r_info);
317 		/* LINTED */
318 		symid = (int)GELF_R_SYM(rela.r_info);
319 		/* LINTED */
320 		if ((symid > (no_syms - 1)) || (symid < 0)) {
321 			(void) fprintf(stderr, "%s: %s: invalid symbol table "
322 			    "offset - %d - in %s\n", prog_name, filename,
323 			    symid, p_scns->scn_name);
324 			ndx++;
325 			continue;
326 		}
327 		(void) gelf_getsym(sym_data, symid, &sym);
328 		sym_name = (char *)elf_strptr(elf_file,
329 			reloc_symtab->p_shdr.sh_link, sym.st_name);
330 		if (sym_name == NULL)
331 			sym_name = (char *)UNKNOWN;
332 		if (r_flag && rn_flag) {
333 			if (strcmp(name, p_scns->scn_name) != 0) {
334 				ndx++;
335 				continue;
336 			}
337 			if (!n_title) {
338 				(void) printf("\n%s:\n", p_scns->scn_name);
339 				(void) printf("%-*s%-*s%-*s%s\n\n",
340 				    12 + adj, "Offset", 22, "Symndx",
341 				    16, "Type", "Addend");
342 				n_title = 1;
343 			}
344 		}
345 		if (d_flag) {
346 			if (!d_hi)
347 				d_hi = d_low;
348 			if ((symid < d_low) || (symid > d_hi)) {
349 				ndx++;
350 				continue;
351 			}
352 		}
353 
354 		(void) printf("%-#*llx", 12 + adj, EC_XWORD(rela.r_offset));
355 		if (!v_flag) {
356 			(void) printf("%-22d%-18d", symid, type);
357 		} else {
358 			if (strlen(sym_name)) {
359 				size_t len = strlen(sym_name) + 1;
360 				char tmpstr[10];
361 				if (len > 22) {
362 					(void) sprintf(tmpstr, "%%-%ds",
363 						/* LINTED */
364 						(int)len);
365 					(void) printf(tmpstr, sym_name);
366 				} else
367 					(void) printf("%-22s", sym_name);
368 			} else
369 				(void) printf("%-22d", symid);
370 			print_reloc_type(p_ehdr->e_machine, type);
371 		}
372 		(void) printf("%lld\n", EC_SXWORD(rela.r_addend));
373 		ndx++;
374 	}
375 }
376 
377 /*
378  * Print relocation data of type SHT_REL.
379  * If d_flag, print data corresponding only to
380  * the section or range of sections specified.
381  * If n_flag, print data corresponding only to
382  * the named section.
383  */
384 static void
385 print_rel(Elf *elf_file, SCNTAB *p_scns, Elf_Data *rdata, Elf_Data *sym_data,
386 	GElf_Ehdr *p_ehdr, size_t reloc_size, size_t sym_size, char *filename,
387 	SCNTAB *reloc_symtab)
388 {
389 	GElf_Rel rel;
390 	GElf_Sym sym;
391 	size_t no_entries;
392 	size_t rel_entsize;
393 	int type, symid;
394 	size_t no_syms;
395 	static int n_title = 0;
396 	int ndx = 0;
397 	char *sym_name;
398 	int adj = 0;
399 
400 	if (gelf_getclass(elf_file) == ELFCLASS64)
401 		adj = 8;
402 
403 	rel_entsize = p_scns->p_shdr.sh_entsize;
404 	if ((rel_entsize == 0) ||
405 	    (rel_entsize > p_scns->p_shdr.sh_size)) {
406 		rel_entsize = gelf_fsize(elf_file, ELF_T_REL, 1,
407 		    EV_CURRENT);
408 	}
409 	no_entries = reloc_size / rel_entsize;
410 
411 	no_syms = sym_size / gelf_fsize(elf_file, ELF_T_SYM, 1, EV_CURRENT);
412 	while (no_entries--) {
413 		(void) gelf_getrel(rdata, ndx, &rel);
414 		/* LINTED */
415 		type = (int)GELF_R_TYPE(rel.r_info);
416 		/* LINTED */
417 		symid = (int)GELF_R_SYM(rel.r_info);
418 		/* LINTED */
419 		if ((symid > (no_syms - 1)) || (symid < 0)) {
420 			(void) fprintf(stderr, "%s: %s: invalid symbol table "
421 			    "offset - %d - in %s\n", prog_name, filename,
422 			    symid, p_scns->scn_name);
423 			ndx++;
424 			continue;
425 		}
426 		(void) gelf_getsym(sym_data, symid, &sym);
427 		sym_name = (char *)elf_strptr(elf_file,
428 			reloc_symtab->p_shdr.sh_link, sym.st_name);
429 		if (sym_name == NULL)
430 			sym_name = (char *)UNKNOWN;
431 		if (r_flag && rn_flag) {
432 			if (strcmp(name, p_scns->scn_name) != 0) {
433 				ndx++;
434 				continue;
435 			}
436 			if (!n_title) {
437 				(void) printf("\n%s:\n", p_scns->scn_name);
438 				(void) printf("%-*s%-*s%s\n\n",
439 				    12 + adj, "Offset", 20, "Symndx", "Type");
440 				n_title = 1;
441 			}
442 		}
443 		if (d_flag) {
444 			if (!d_hi)
445 				d_hi = d_low;
446 			if ((symid < d_low) || (symid > d_hi)) {
447 				ndx++;
448 				continue;
449 			}
450 		}
451 
452 		(void) printf("%-#*llx", 12 + adj, EC_ADDR(rel.r_offset));
453 		if (!v_flag) {
454 			(void) printf("%-20d%-18d", symid, type);
455 		} else {
456 			if (strlen(sym_name))
457 				(void) printf("%-20s", sym_name);
458 			else
459 				(void) printf("%-20d", sym.st_name);
460 
461 			print_reloc_type(p_ehdr->e_machine, type);
462 		}
463 		(void) printf("\n");
464 		ndx++;
465 	}
466 }
467 
468 /* demangle C++ names */
469 static char *
470 demangled_name(char *s)
471 {
472 	static char	*buf = NULL;
473 	char		*dn;
474 	size_t		len;
475 
476 	dn = sgs_demangle(s);
477 
478 	/*
479 	 * If not demangled, just return the symbol name
480 	 */
481 	if (strcmp(s, dn) == 0)
482 		return (s);
483 
484 	/*
485 	 * Demangled. Format it
486 	 */
487 	if (buf != NULL)
488 		free(buf);
489 
490 	len = strlen(dn) + strlen(s) + 4;
491 	if ((buf = malloc(len)) == NULL)
492 		return (s);
493 
494 	(void) snprintf(buf, len, "%s\t[%s]", dn, s);
495 	return (buf);
496 }
497 
498 /*
499  * Print the symbol table.  Input is an ELF file descriptor, a
500  * pointer to the symbol table SCNTAB structure,
501  * the number of symbols, a range of symbols to print,
502  * an index which is the number of the
503  * section in the file, and the filename.  The number of sections,
504  * the range, and the index are set in
505  * dump_symbol_table, depending on whether -n or -T were set.
506  */
507 static void
508 print_symtab(Elf *elf_file, SCNTAB *p_symtab, Elf_Data *sym_data,
509 	long range, int index)
510 {
511 	GElf_Sym sym;
512 	int adj = 0;		/* field adjustment for elf64 */
513 	Elf32_Word	*symshndx = 0;
514 	unsigned int	nosymshndx = 0;
515 
516 	if (gelf_getclass(elf_file) == ELFCLASS64)
517 		adj = 8;
518 
519 	while (range > 0) {
520 		char		*sym_name = (char *)0;
521 		int		type, bind;
522 		int		specsec;
523 		unsigned int	shndx;
524 
525 		(void) gelf_getsym(sym_data, index, &sym);
526 		type = (int)GELF_ST_TYPE(sym.st_info);
527 		bind = (int)GELF_ST_BIND(sym.st_info);
528 
529 		if ((sym.st_shndx == SHN_XINDEX) &&
530 		    (symshndx == 0) && (nosymshndx == 0)) {
531 			Elf_Scn		*_scn;
532 			GElf_Shdr	_shdr;
533 			size_t		symscnndx;
534 
535 			symscnndx = elf_ndxscn(p_symtab->p_sd);
536 			_scn = 0;
537 			while ((_scn = elf_nextscn(elf_file, _scn)) != 0) {
538 				if (gelf_getshdr(_scn, &_shdr) == 0)
539 					break;
540 				if ((_shdr.sh_type == SHT_SYMTAB_SHNDX) &&
541 				    /* LINTED */
542 				    (_shdr.sh_link == (GElf_Word)symscnndx)) {
543 					Elf_Data	*_data;
544 
545 					if ((_data = elf_getdata(_scn, 0)) == 0)
546 						continue;
547 
548 					symshndx = (Elf32_Word *)_data->d_buf;
549 					nosymshndx = 0;
550 					break;
551 				}
552 			}
553 			nosymshndx = 1;
554 		}
555 
556 		if ((symshndx) && (sym.st_shndx == SHN_XINDEX)) {
557 			shndx = symshndx[index];
558 			specsec = 0;
559 		} else {
560 			shndx = sym.st_shndx;
561 			if ((sym.st_shndx == SHN_UNDEF) ||
562 			    (sym.st_shndx >= SHN_LORESERVE))
563 				specsec = 1;
564 			else
565 				specsec = 0;
566 		}
567 
568 
569 		(void) printf("[%d]\t ", index++);
570 
571 		if (v_flag && (type == STT_SPARC_REGISTER)) {
572 			/*
573 			 *  The strings "REG_G1" through "REG_G7" are intended
574 			 *  to be consistent with output from elfdump(1).
575 			 */
576 			switch (sym.st_value) {
577 			case STO_SPARC_REGISTER_G1:
578 				(void) printf("%-*s", 12 + adj, "REG_G1");
579 				break;
580 			case STO_SPARC_REGISTER_G2:
581 				(void) printf("%-*s", 12 + adj, "REG_G2");
582 				break;
583 			case STO_SPARC_REGISTER_G3:
584 				(void) printf("%-*s", 12 + adj, "REG_G3");
585 				break;
586 			case STO_SPARC_REGISTER_G4:
587 				(void) printf("%-*s", 12 + adj, "REG_G4");
588 				break;
589 			case STO_SPARC_REGISTER_G5:
590 				(void) printf("%-*s", 12 + adj, "REG_G5");
591 				break;
592 			case STO_SPARC_REGISTER_G6:
593 				(void) printf("%-*s", 12 + adj, "REG_G6");
594 				break;
595 			case STO_SPARC_REGISTER_G7:
596 				(void) printf("%-*s", 12 + adj, "REG_G7");
597 				break;
598 			default:
599 				(void) printf("0x%-*llx", 10 + adj,
600 				    EC_ADDR(sym.st_value));
601 			}
602 		} else
603 			(void) printf("0x%-*llx", 10 + adj,
604 			    EC_ADDR(sym.st_value));
605 
606 		(void) printf("%-*lld", 9 + adj, EC_XWORD(sym.st_size));
607 
608 		if (!v_flag) {
609 			(void) printf("%d\t\t%d\t%d\t%#x\t",
610 			    type, bind, (int)sym.st_other, (int)shndx);
611 		} else {
612 			switch (type) {
613 			case STT_NOTYPE:
614 				(void) printf("%s\t", "NOTY");
615 				break;
616 			case STT_OBJECT:
617 				(void) printf("%s\t", "OBJT");
618 				break;
619 			case STT_FUNC:
620 				(void) printf("%s\t", "FUNC");
621 				break;
622 			case STT_SECTION:
623 				(void) printf("%s\t", "SECT");
624 				break;
625 			case STT_FILE:
626 				(void) printf("%s\t", "FILE");
627 				break;
628 			case STT_SPARC_REGISTER:
629 				(void) printf("%s\t", "REGI");
630 				break;
631 			case STT_COMMON:
632 				(void) printf("%s\t", "COMM");
633 				break;
634 			case STT_TLS:
635 				(void) printf("%s\t", "TLS ");
636 				break;
637 			default:
638 				(void) printf("%d\t", type);
639 			}
640 			switch (bind) {
641 			case STB_LOCAL:
642 				(void) printf("LOCL");
643 				break;
644 			case STB_GLOBAL:
645 				(void) printf("GLOB");
646 				break;
647 			case STB_WEAK:
648 				(void) printf("WEAK");
649 				break;
650 			default:
651 				(void) printf("%d", bind);
652 			}
653 			(void) printf("\t  %d\t", EC_WORD(sym.st_other));
654 
655 			if (specsec) {
656 				switch (shndx) {
657 				case SHN_UNDEF:
658 					(void) printf("UNDEF");
659 					break;
660 				case SHN_ABS:
661 					(void) printf("ABS");
662 					break;
663 				case SHN_COMMON:
664 					(void) printf("COMMON");
665 					break;
666 				case SHN_XINDEX:
667 					(void) printf("XINDEX");
668 					break;
669 				default:
670 					(void) printf("%d", EC_WORD(shndx));
671 				}
672 			} else
673 				(void) printf("%d", EC_WORD(shndx));
674 			(void) printf("\t");
675 		}
676 
677 		/* support machines where NULL-deref causes core dump */
678 		if (sym.st_name == 0)
679 			sym_name = (char *)UNKNOWN;
680 		else
681 			if (C_flag)
682 				sym_name = demangled_name(
683 					(char *)elf_strptr(elf_file,
684 					p_symtab->p_shdr.sh_link,
685 					sym.st_name));
686 		else
687 			sym_name = (char *)elf_strptr(elf_file,
688 				p_symtab->p_shdr.sh_link,
689 				sym.st_name);
690 		if (sym_name == NULL)
691 			sym_name = (char *)UNKNOWN;
692 		(void) printf("%s\n", sym_name);
693 
694 		range--;
695 	}	/* end while */
696 }
697 
698 /*
699  * Print the section header table.  Input is the SCNTAB structure,
700  * the number of sections, an index which is the number of the
701  * section in the file, and the filename.  The values of the SCNTAB
702  * structure, the number of sections, and the index are set in
703  * dump_shdr depending on whether the -n or -d modifiers were set.
704  */
705 static void
706 print_shdr(Elf *elf_file, SCNTAB *s, int num_scns, int index)
707 {
708 	SCNTAB *p;
709 	int num;
710 	int field;
711 
712 	if (gelf_getclass(elf_file) == ELFCLASS64)
713 		field = 21;
714 	else
715 		field = 13;
716 
717 	p = s;
718 
719 	for (num = 0; num < num_scns; num++, p++) {
720 		(void) printf("[%d]\t", index++);
721 		if (!v_flag) {
722 			(void) printf("%u\t%llu\t",
723 			EC_WORD(p->p_shdr.sh_type),
724 			EC_XWORD(p->p_shdr.sh_flags));
725 		} else {
726 			switch (p->p_shdr.sh_type) {
727 			case SHT_NULL:
728 				(void) printf("NULL");
729 				break;
730 			case SHT_PROGBITS:
731 				(void) printf("PBIT");
732 				break;
733 			case SHT_SYMTAB:
734 				(void) printf("SYMT");
735 				break;
736 			case SHT_STRTAB:
737 				(void) printf("STRT");
738 				break;
739 			case SHT_RELA:
740 				(void) printf("RELA");
741 				break;
742 			case SHT_HASH:
743 				(void) printf("HASH");
744 				break;
745 			case SHT_DYNAMIC:
746 				(void) printf("DYNM");
747 				break;
748 			case SHT_NOTE:
749 				(void) printf("NOTE");
750 				break;
751 			case SHT_NOBITS:
752 				(void) printf("NOBI");
753 				break;
754 			case SHT_REL:
755 				(void) printf("REL ");
756 				break;
757 			case SHT_DYNSYM:
758 				(void) printf("DYNS");
759 				break;
760 			case ((GElf_Word) SHT_LOUSER):
761 				(void) printf("LUSR");
762 				break;
763 			case ((GElf_Word) SHT_HIUSER):
764 				(void) printf("HUSR");
765 				break;
766 			case SHT_SHLIB:
767 				(void) printf("SHLB");
768 				break;
769 			case SHT_SUNW_SIGNATURE:
770 				(void) printf("SIGN");
771 				break;
772 			case SHT_SUNW_ANNOTATE:
773 				(void) printf("ANOT");
774 				break;
775 			case SHT_SUNW_DEBUGSTR:
776 				(void) printf("DBGS");
777 				break;
778 			case SHT_SUNW_DEBUG:
779 				(void) printf("DBG ");
780 				break;
781 			case SHT_SUNW_move:
782 				(void) printf("MOVE");
783 				break;
784 			case SHT_SUNW_verdef:
785 				(void) printf("VERD");
786 				break;
787 			case SHT_SUNW_verneed:
788 				(void) printf("VERN");
789 				break;
790 			case SHT_SUNW_versym:
791 				(void) printf("VERS");
792 				break;
793 			case SHT_SUNW_syminfo:
794 				(void) printf("SYMI");
795 				break;
796 			case SHT_SUNW_COMDAT:
797 				(void) printf("COMD");
798 				break;
799 			case SHT_AMD64_UNWIND:
800 				(void) printf("UNWD");
801 				break;
802 			case SHT_SPARC_GOTDATA:
803 				(void) printf("GOTD");
804 				break;
805 			default:
806 				(void) printf("%u", EC_WORD(p->p_shdr.sh_type));
807 				break;
808 			}
809 			(void) printf("    ");
810 
811 			if (p->p_shdr.sh_flags & SHF_WRITE)
812 				(void) printf("W");
813 			else
814 				(void) printf("-");
815 			if (p->p_shdr.sh_flags & SHF_ALLOC)
816 				(void) printf("A");
817 			else
818 				(void) printf("-");
819 			if (p->p_shdr.sh_flags & SHF_EXECINSTR)
820 				(void) printf("I");
821 			else
822 				(void) printf("-");
823 
824 			if (p->p_shdr.sh_flags & SHF_ORDERED)
825 				(void) printf("O");
826 			if (p->p_shdr.sh_flags & SHF_EXCLUDE)
827 				(void) printf("E");
828 
829 			(void) printf("\t");
830 
831 		}
832 		(void) printf("%-#*llx%-#*llx%-#*llx%s%s\n",
833 			field, EC_ADDR(p->p_shdr.sh_addr),
834 			field, EC_OFF(p->p_shdr.sh_offset),
835 			field, EC_XWORD(p->p_shdr.sh_size),
836 			/* compatibility:  tab for elf32 */
837 			(field == 13) ? "\t" : " ", p->scn_name);
838 
839 		(void) printf("\t%u\t%u\t%-#*llx%-#*llx\n\n",
840 			EC_WORD(p->p_shdr.sh_link),
841 			EC_WORD(p->p_shdr.sh_info),
842 			field, EC_XWORD(p->p_shdr.sh_addralign),
843 			field, EC_XWORD(p->p_shdr.sh_entsize));
844 	}
845 }
846 
847 /*
848  * Check that a range of numbers is valid.  Input is
849  * a lower bound, an upper bound, a boundary condition,
850  * and the filename.  Negative numbers and numbers greater
851  * than the bound are invalid.  low must be smaller than hi.
852  * The returned integer is the number of items in the
853  * range if it is valid and -1 otherwise.
854  */
855 static int
856 check_range(int low, int hi, size_t bound, char *filename)
857 {
858 	if (((size_t)low > bound) || (low <= 0)) {
859 		(void) fprintf(stderr,
860 			"%s: %s: number out of range, %d\n",
861 			prog_name, filename, low);
862 		return (-1);
863 	}
864 	if (((size_t)hi > bound) || (hi < 0)) {
865 		(void) fprintf(stderr,
866 			"%s: %s: number out of range, %d\n",
867 			prog_name, filename, hi);
868 			return (-1);
869 	}
870 
871 	if (hi && (low > hi)) {
872 		(void) fprintf(stderr,
873 			"%s: %s: invalid range, %d,%d\n",
874 			prog_name, filename, low, hi);
875 		return (-1);
876 	}
877 	if (hi)
878 		return (hi - low + 1);
879 	else
880 		return (1);
881 }
882 
883 /*
884  * Print relocation information.  Since this information is
885  * machine dependent, new sections must be added for each machine
886  * that is supported.  Input is an ELF file descriptor, the ELF header,
887  * the SCNTAB structure, the number of sections, and a filename.
888  * Set up necessary information to print relocation information
889  * and call the appropriate print function depending on the
890  * type of relocation information.  If the symbol table is
891  * absent, no relocation data is processed.  Input is an
892  * ELF file descriptor, the ELF header, the SCNTAB structure,
893  * and the filename.  Set range of d_flag and name if n_flag.
894  */
895 static void
896 dump_reloc_table(Elf *elf_file, GElf_Ehdr *p_ehdr,
897 	SCNTAB *p_scns, int num_scns, char *filename)
898 {
899 	Elf_Data *rel_data;
900 	Elf_Data *sym_data;
901 	size_t    sym_size;
902 	size_t    reloc_size;
903 	SCNTAB *reloc_symtab;
904 	SCNTAB *head_scns;
905 	int r_title = 0;
906 	int adj = 0;
907 	size_t shnum;
908 
909 	if (gelf_getclass(elf_file) == ELFCLASS64)
910 		adj = 8;
911 
912 	if ((!p_flag) && (!r_title)) {
913 		(void) printf("\n    **** RELOCATION INFORMATION ****\n");
914 		r_title = 1;
915 	}
916 
917 	while (num_scns-- > 0) {
918 		if ((p_scns->p_shdr.sh_type != SHT_RELA) &&
919 		    (p_scns->p_shdr.sh_type != SHT_REL)) {
920 			p_scns++;
921 			continue;
922 		}
923 
924 	head_scns = p_head_scns;
925 
926 	if (elf_getshnum(elf_file, &shnum) == 0) {
927 		(void) fprintf(stderr,
928 			"%s: %s: elf_getshnum failed: %s\n",
929 			prog_name, filename, elf_errmsg(-1));
930 		return;
931 	}
932 
933 	if ((p_scns->p_shdr.sh_link == 0) ||
934 	    /* LINTED */
935 	    (p_scns->p_shdr.sh_link >= (GElf_Word)shnum)) {
936 		(void) fprintf(stderr, "%s: %s: invalid sh_link field: "
937 			"section #: %d sh_link: %d\n",
938 			/* LINTED */
939 			prog_name, filename, (int)elf_ndxscn(p_scns->p_sd),
940 			(int)p_scns->p_shdr.sh_link);
941 		return;
942 	}
943 	head_scns += (p_scns->p_shdr.sh_link -1);
944 
945 	if (head_scns->p_shdr.sh_type == SHT_SYMTAB) {
946 		reloc_symtab = p_symtab;
947 	} else if (head_scns->p_shdr.sh_type  == SHT_DYNSYM) {
948 		reloc_symtab = p_dynsym;
949 	} else {
950 		(void) fprintf(stderr,
951 "%s: %s: could not get symbol table\n", prog_name, filename);
952 		return;
953 	}
954 
955 	sym_data = NULL;
956 	sym_size = 0;
957 	reloc_size = 0;
958 
959 	if ((sym_data = elf_getdata(reloc_symtab->p_sd, NULL)) == NULL) {
960 		(void) fprintf(stderr,
961 		"%s: %s: no symbol table data\n", prog_name, filename);
962 		return;
963 	}
964 	sym_size = sym_data->d_size;
965 
966 	if (p_scns == NULL) {
967 		(void) fprintf(stderr,
968 		"%s: %s: no section table data\n", prog_name, filename);
969 		return;
970 	}
971 
972 	if (p_scns->p_shdr.sh_type == SHT_RELA) {
973 		if (!n_flag && r_flag)
974 			(void) printf("\n%s:\n", p_scns->scn_name);
975 		if (!p_flag && (!n_flag && r_flag))
976 			(void) printf("%-*s%-*s%-*s%s\n\n",
977 			    12 + adj, "Offset", 22, "Symndx",
978 			    18, "Type", "Addend");
979 		if ((rel_data = elf_getdata(p_scns->p_sd, NULL)) == NULL) {
980 			(void) fprintf(stderr,
981 "%s: %s: no relocation information\n", prog_name, filename);
982 			return;
983 		}
984 		reloc_size = rel_data->d_size;
985 
986 		if (n_flag) {
987 			rn_flag = 1;
988 			print_rela(elf_file, p_scns, rel_data, sym_data, p_ehdr,
989 				reloc_size, sym_size, filename, reloc_symtab);
990 		}
991 		if (d_flag) {
992 			rn_flag = 0;
993 			print_rela(elf_file, p_scns, rel_data, sym_data, p_ehdr,
994 				reloc_size, sym_size, filename, reloc_symtab);
995 		}
996 		if (!n_flag && !d_flag)
997 			print_rela(elf_file, p_scns, rel_data, sym_data, p_ehdr,
998 				reloc_size, sym_size, filename, reloc_symtab);
999 	} else {
1000 		if (p_scns->p_shdr.sh_type == SHT_REL) {
1001 			if (!n_flag && r_flag)
1002 				(void) printf("\n%s:\n", p_scns->scn_name);
1003 			if (!p_flag && (!n_flag && r_flag)) {
1004 				(void) printf("%-*s%-*s%s\n\n",
1005 				    12 + adj, "Offset", 20, "Symndx", "Type");
1006 			}
1007 			if ((rel_data = elf_getdata(p_scns->p_sd, NULL))
1008 			    == NULL) {
1009 				(void) fprintf(stderr,
1010 "%s: %s: no relocation information\n", prog_name, filename);
1011 				return;
1012 			}
1013 			reloc_size = rel_data->d_size;
1014 			if (n_flag) {
1015 				rn_flag = 1;
1016 				print_rel(elf_file, p_scns, rel_data, sym_data,
1017 					p_ehdr, reloc_size, sym_size,
1018 					filename, reloc_symtab);
1019 			}
1020 			if (d_flag) {
1021 				rn_flag = 0;
1022 				print_rel(elf_file, p_scns, rel_data, sym_data,
1023 					p_ehdr, reloc_size, sym_size,
1024 					filename, reloc_symtab);
1025 			}
1026 			if (!n_flag && !d_flag)
1027 				print_rel(elf_file, p_scns, rel_data, sym_data,
1028 					p_ehdr, reloc_size, sym_size,
1029 					filename, reloc_symtab);
1030 		}
1031 	}
1032 	p_scns++;
1033 	}
1034 }
1035 
1036 /*
1037  * Print out the string tables.  Input is an opened ELF file,
1038  * the SCNTAB structure, the number of sections, and the filename.
1039  * Since there can be more than one string table, all sections are
1040  * examined and any with the correct type are printed out.
1041  */
1042 static void
1043 dump_string_table(SCNTAB *s, int num_scns)
1044 {
1045 	size_t section_size;
1046 	unsigned char *strtab;
1047 	int beg_of_string;
1048 	int counter = 0;
1049 	int str_off;
1050 	int i;
1051 
1052 	if (!p_flag) {
1053 		(void) printf("\n     **** STRING TABLE INFORMATION ****\n");
1054 	}
1055 
1056 	for (i = 0; i < num_scns; i++, s++) {
1057 		if (s->p_shdr.sh_type != SHT_STRTAB)
1058 			continue;
1059 
1060 		str_off = 0;
1061 
1062 		if (!p_flag) {
1063 			(void) printf("\n%s:\n", s->scn_name);
1064 			(void) printf("   <offset>  \tName\n");
1065 		}
1066 		section_size = 0;
1067 		if ((strtab = (unsigned char *)
1068 		    get_scndata(s->p_sd, &section_size)) == NULL) {
1069 			continue;
1070 		}
1071 
1072 		if (section_size != 0) {
1073 			(void) printf("   <%d>  \t", str_off);
1074 			beg_of_string = 0;
1075 			while (section_size--) {
1076 				unsigned char c = *strtab++;
1077 
1078 				if (beg_of_string) {
1079 					(void) printf("   <%d>  \t", str_off);
1080 					counter++;
1081 					beg_of_string = 0;
1082 				}
1083 				str_off++;
1084 				switch (c) {
1085 				case '\0':
1086 					(void) printf("\n");
1087 					beg_of_string = 1;
1088 					break;
1089 				default:
1090 					(void) putchar(c);
1091 				}
1092 			}
1093 		}
1094 	}
1095 	(void) printf("\n");
1096 }
1097 
1098 /*
1099  * Print the symbol table.  This function does not print the contents
1100  * of the symbol table but sets up the parameters and then calls
1101  * print_symtab to print the symbols.  Calling another function to print
1102  * the symbols allows both -T and -n to work correctly
1103  * simultaneously.  Input is an opened ELF file, a pointer to the
1104  * symbol table SCNTAB structure, and the filename.
1105  * Set the range of symbols to print if T_flag, and set
1106  * name of symbol to print if n_flag.
1107  */
1108 static void
1109 dump_symbol_table(Elf *elf_file, SCNTAB *p_symtab, char *filename)
1110 {
1111 	Elf_Data  *sym_data;
1112 	GElf_Sym  T_range, n_range;	/* for use with -T and -n */
1113 	size_t count = 0;
1114 	size_t sym_size;
1115 	int index = 1;
1116 	int found_it = 0;
1117 	int i;
1118 	int adj = 0;			/*  field adjustment for elf64 */
1119 
1120 	if (gelf_getclass(elf_file) == ELFCLASS64)
1121 		adj = 8;
1122 
1123 	if (p_symtab == NULL) {
1124 		(void) fprintf(stderr,
1125 		"%s: %s: could not get symbol table\n", prog_name, filename);
1126 		return;
1127 	}
1128 
1129 	/* get symbol table data */
1130 	sym_data = NULL;
1131 	sym_size = 0;
1132 	if ((sym_data =
1133 	    elf_getdata(p_symtab->p_sd, NULL)) == NULL) {
1134 		(void) printf("\n%s:\n", p_symtab->scn_name);
1135 		(void) printf("No symbol table data\n");
1136 		return;
1137 	}
1138 	sym_size = sym_data->d_size;
1139 
1140 	count = sym_size / p_symtab->p_shdr.sh_entsize;
1141 
1142 	if (n_flag && t_flag && !T_flag) {
1143 		/* LINTED */
1144 		for (i = 1; i < count; i++) {
1145 			(void) gelf_getsym(sym_data, i, &n_range);
1146 			if (strcmp(name, (char *)
1147 			    elf_strptr(elf_file,
1148 			    p_symtab->p_shdr.sh_link,
1149 			    n_range.st_name)) != 0) {
1150 				continue;
1151 			} else {
1152 				found_it = 1;
1153 				if (!p_flag) {
1154 					(void) printf(
1155 "\n              ***** SYMBOL TABLE INFORMATION *****\n");
1156 					(void) printf(
1157 "[Index]  %-*s%-*sType\tBind\tOther\tShndx\tName",
1158 			    12 + adj, "Value", 9 + adj, "Size");
1159 				}
1160 				(void) printf("\n%s:\n", p_symtab->scn_name);
1161 				print_symtab(elf_file, p_symtab, sym_data,
1162 				    1, i);
1163 			}
1164 		}   /* end for */
1165 		if (!found_it) {
1166 			(void) fprintf(stderr, "%s: %s: %s not found\n",
1167 			prog_name, filename, name);
1168 		}
1169 	} else if (T_flag) {
1170 		T_num = check_range(T_low, T_hi, count, filename);
1171 		if (T_num < 0)
1172 			return;
1173 
1174 		(void) gelf_getsym(sym_data, T_low-1, &T_range);
1175 		index = T_low;
1176 
1177 		if (!p_flag) {
1178 			(void) printf(
1179 "\n              ***** SYMBOL TABLE INFORMATION *****\n");
1180 			(void) printf(
1181 "[Index]  %-*s%-*sType\tBind\tOther\tShndx\tName",
1182 			    12 + adj, "Value", 9 + adj, "Size");
1183 		}
1184 		(void) printf("\n%s:\n", p_symtab->scn_name);
1185 		print_symtab(elf_file, p_symtab, sym_data, T_num, index);
1186 	} else {
1187 		if (!p_flag) {
1188 			(void) printf(
1189 "\n              ***** SYMBOL TABLE INFORMATION *****\n");
1190 			(void) printf(
1191 "[Index]  %-*s%-*sType\tBind\tOther\tShndx\tName",
1192 			    12 + adj, "Value", 9 + adj, "Size");
1193 		}
1194 		(void) printf("\n%s:\n", p_symtab->scn_name);
1195 		print_symtab(elf_file, p_symtab, sym_data, count-1, 1);
1196 	}
1197 }
1198 
1199 
1200 /*
1201  * The items in a dynamic section are displayed using a small set
1202  * of standard output styles. To reduce code size and promote
1203  * consistency, the following family of functions, all named
1204  * with the prefix "pdynitem_", are used by dump_dynamic().
1205  *
1206  * entry:
1207  *	name - Name of element
1208  *	p_dyn - Pointer to struct describing element
1209  *	elf_file, link - Used to look up a string from the string table
1210  *		in the ELF file.
1211  *	bitdesc - Pointer to NULL terminated array of PDYNITEM_BITDESC
1212  *		structs describing the allowed bit values.
1213  */
1214 #define	Fmttag		"%-15.15s "
1215 #define	Fmtptr		"%#llx"
1216 
1217 void
1218 pdynitem_addr(const char *name, GElf_Dyn *p_dyn)
1219 {
1220 	(void) printf(Fmttag, name);
1221 	(void) printf(Fmtptr, EC_ADDR(p_dyn->d_un.d_ptr));
1222 }
1223 
1224 void
1225 pdynitem_val(const char *name, GElf_Dyn *p_dyn)
1226 {
1227 	(void) printf(Fmttag, name);
1228 	(void) printf(Fmtptr, EC_XWORD(p_dyn->d_un.d_val));
1229 }
1230 
1231 void
1232 pdynitem_depval(const char *name, GElf_Dyn *p_dyn)
1233 {
1234 	(void) printf(Fmttag, name);
1235 	(void) printf(Fmtptr "  (deprecated value)",
1236 			EC_XWORD(p_dyn->d_un.d_val));
1237 }
1238 
1239 void
1240 pdynitem_ign(const char *name)
1241 {
1242 	(void) printf(Fmttag "(ignored)", name);
1243 }
1244 
1245 void
1246 pdynitem_str(const char *name, GElf_Dyn *p_dyn, Elf *elf_file, GElf_Word link)
1247 {
1248 	char *str;
1249 
1250 	(void) printf(Fmttag, name);
1251 	if (v_flag) {	/* Look up the string */
1252 		str = (char *)elf_strptr(elf_file, link, p_dyn->d_un.d_ptr);
1253 		if (!(str && *str))
1254 			str = (char *)UNKNOWN;
1255 		(void) printf("%s", str);
1256 	} else {	/* Show the address */
1257 		(void) printf(Fmtptr, EC_ADDR(p_dyn->d_un.d_ptr));
1258 	}
1259 }
1260 
1261 /*
1262  * Arrays of this type are used for the values argument to
1263  * pdynitem_bitmask(). It maps a bit value to a human readable
1264  * name string. The final element of such an array must always
1265  * be NULL.
1266  */
1267 typedef struct {
1268 	int bit;		/* Bit Value */
1269 	const char *name;	/* Name corresponding to bit */
1270 } PDYNITEM_BITDESC;
1271 
1272 void
1273 pdynitem_bitmask(const char *name, GElf_Dyn *p_dyn, PDYNITEM_BITDESC *bitdesc)
1274 {
1275 	char buf[512];
1276 
1277 	(void) printf(Fmttag, name);
1278 	if (v_flag) {
1279 		buf[0] = '\0';
1280 		for (; bitdesc->bit; bitdesc++) {
1281 			if (p_dyn->d_un.d_val &	bitdesc->bit)
1282 				(void) strlcat(buf, bitdesc->name,
1283 					sizeof (buf));
1284 		}
1285 		if (buf[0]) {
1286 			(void) printf("%s", buf);
1287 			return;
1288 		}
1289 	}
1290 
1291 	/* We don't have a string, or one is not requested. Show address */
1292 	(void) printf(Fmtptr, EC_ADDR(p_dyn->d_un.d_ptr));
1293 
1294 }
1295 
1296 #undef Fmttag
1297 #undef Fmtptr
1298 
1299 /*
1300  * Print dynamic linking information.  Input is an ELF
1301  * file descriptor, the SCNTAB structure, the number of
1302  * sections, and the filename.
1303  */
1304 static void
1305 dump_dynamic(Elf *elf_file, SCNTAB *p_scns, int num_scns, char *filename)
1306 {
1307 	/*
1308 	 * Map dynamic bit fields to readable strings. These tables
1309 	 * must be kept in sync with the definitions in <link.h>.
1310 	 *
1311 	 * The string displayed is always the same as the name used
1312 	 * for the constant, with the prefix removed. The BITDESC macro
1313 	 * generate both PDYNITEM_BITDESC fields from the base name.
1314 	 */
1315 #define	BITDESC(prefix, item) { prefix ## item, #item " " }
1316 
1317 	static PDYNITEM_BITDESC dyn_dt_flags[] = {	/* DT_FLAGS */
1318 		BITDESC(DF_, ORIGIN),
1319 		BITDESC(DF_, SYMBOLIC),
1320 		BITDESC(DF_, TEXTREL),
1321 		BITDESC(DF_, BIND_NOW),
1322 		BITDESC(DF_, STATIC_TLS),
1323 		{ 0 }
1324 	};
1325 
1326 	static PDYNITEM_BITDESC dyn_dt_flags_1[] = {	/* DT_FLAGS_1 */
1327 		BITDESC(DF_1_, NOW),
1328 		BITDESC(DF_1_, GLOBAL),
1329 		BITDESC(DF_1_, GROUP),
1330 		BITDESC(DF_1_, NODELETE),
1331 		BITDESC(DF_1_, LOADFLTR),
1332 		BITDESC(DF_1_, INITFIRST),
1333 		BITDESC(DF_1_, NOOPEN),
1334 		BITDESC(DF_1_, ORIGIN),
1335 		BITDESC(DF_1_, DIRECT),
1336 		BITDESC(DF_1_, TRANS),
1337 		BITDESC(DF_1_, INTERPOSE),
1338 		BITDESC(DF_1_, NODEFLIB),
1339 		BITDESC(DF_1_, NODUMP),
1340 		BITDESC(DF_1_, CONFALT),
1341 		BITDESC(DF_1_, ENDFILTEE),
1342 		BITDESC(DF_1_, DISPRELDNE),
1343 		BITDESC(DF_1_, DISPRELPND),
1344 		BITDESC(DF_1_, NODIRECT),
1345 		BITDESC(DF_1_, IGNMULDEF),
1346 		BITDESC(DF_1_, NOKSYMS),
1347 		BITDESC(DF_1_, NOHDR),
1348 		BITDESC(DF_1_, NORELOC),
1349 		{ 0 }
1350 	};
1351 
1352 	static PDYNITEM_BITDESC dyn_dt_feature_1[] = {	/* DT_FEATURE_1 */
1353 		BITDESC(DTF_1_, PARINIT),
1354 		BITDESC(DTF_1_, CONFEXP),
1355 		{ 0 }
1356 	};
1357 
1358 	static PDYNITEM_BITDESC dyn_dt_posflag_1[] = {	/* DT_POSFLAG_1 */
1359 		BITDESC(DF_P1_, LAZYLOAD),
1360 		BITDESC(DF_P1_, GROUPPERM),
1361 		{ 0 }
1362 	};
1363 
1364 #undef	BITDESC
1365 
1366 	Elf_Data	*dyn_data;
1367 	GElf_Dyn	p_dyn;
1368 	GElf_Phdr	p_phdr;
1369 	GElf_Ehdr	p_ehdr;
1370 	int		index = 1;
1371 	int		lib_scns = num_scns;
1372 	SCNTAB		*l_scns = p_scns;
1373 	int		header_num = 0;
1374 
1375 	if (!p_flag)
1376 		(void) printf("\n  **** DYNAMIC SECTION INFORMATION ****\n");
1377 
1378 	for (; num_scns > 0; num_scns--, p_scns++) {
1379 		GElf_Word	link;
1380 		int		ii;
1381 
1382 
1383 		if (p_scns->p_shdr.sh_type != SHT_DYNAMIC)
1384 			continue;
1385 
1386 		if (!p_flag) {
1387 			(void) printf("%s:\n", p_scns->scn_name);
1388 			(void) printf("[INDEX]\tTag         Value\n");
1389 		}
1390 
1391 		if ((dyn_data = elf_getdata(p_scns->p_sd, NULL)) == 0) {
1392 			(void) fprintf(stderr, "%s: %s: no data in "
1393 			    "%s section\n", prog_name, filename,
1394 			    p_scns->scn_name);
1395 			return;
1396 		}
1397 
1398 		link = p_scns->p_shdr.sh_link;
1399 		ii = 0;
1400 
1401 		(void) gelf_getdyn(dyn_data, ii++, &p_dyn);
1402 		while (p_dyn.d_tag != DT_NULL) {
1403 			(void) printf("[%d]\t", index++);
1404 
1405 			/*
1406 			 * It would be nice to use a table driven loop
1407 			 * here, but the address space is too sparse
1408 			 * and irregular. A switch is simple and robust.
1409 			 */
1410 			switch (p_dyn.d_tag) {
1411 			/*
1412 			 * Start of generic flags.
1413 			 */
1414 			case (DT_NEEDED):
1415 				pdynitem_str("NEEDED", &p_dyn, elf_file, link);
1416 				break;
1417 			case (DT_PLTRELSZ):
1418 				pdynitem_val("PLTSZ", &p_dyn);
1419 				break;
1420 			case (DT_PLTGOT):
1421 				pdynitem_addr("PLTGOT", &p_dyn);
1422 				break;
1423 			case (DT_HASH):
1424 				pdynitem_addr("HASH", &p_dyn);
1425 				break;
1426 			case (DT_STRTAB):
1427 				pdynitem_addr("STRTAB", &p_dyn);
1428 				break;
1429 			case (DT_SYMTAB):
1430 				pdynitem_addr("SYMTAB", &p_dyn);
1431 				break;
1432 			case (DT_RELA):
1433 				pdynitem_addr("RELA", &p_dyn);
1434 				break;
1435 			case (DT_RELASZ):
1436 				pdynitem_val("RELASZ", &p_dyn);
1437 				break;
1438 			case (DT_RELAENT):
1439 				pdynitem_val("RELAENT", &p_dyn);
1440 				break;
1441 			case (DT_STRSZ):
1442 				pdynitem_val("STRSZ", &p_dyn);
1443 				break;
1444 			case (DT_SYMENT):
1445 				pdynitem_val("SYMENT", &p_dyn);
1446 				break;
1447 			case (DT_INIT):
1448 				pdynitem_addr("INIT", &p_dyn);
1449 				break;
1450 			case (DT_FINI):
1451 				pdynitem_addr("FINI", &p_dyn);
1452 				break;
1453 			case (DT_SONAME):
1454 				pdynitem_str("SONAME", &p_dyn, elf_file, link);
1455 				break;
1456 			case (DT_RPATH):
1457 				pdynitem_str("RPATH", &p_dyn, elf_file, link);
1458 				break;
1459 			case (DT_SYMBOLIC):
1460 				pdynitem_ign("SYMB");
1461 				break;
1462 			case (DT_REL):
1463 				pdynitem_addr("REL", &p_dyn);
1464 				break;
1465 			case (DT_RELSZ):
1466 				pdynitem_val("RELSZ", &p_dyn);
1467 				break;
1468 			case (DT_RELENT):
1469 				pdynitem_val("RELENT", &p_dyn);
1470 				break;
1471 			case (DT_PLTREL):
1472 				pdynitem_val("PLTREL", &p_dyn);
1473 				break;
1474 			case (DT_DEBUG):
1475 				pdynitem_addr("DEBUG", &p_dyn);
1476 				break;
1477 			case (DT_TEXTREL):
1478 				pdynitem_addr("TEXTREL", &p_dyn);
1479 				break;
1480 			case (DT_JMPREL):
1481 				pdynitem_addr("JMPREL", &p_dyn);
1482 				break;
1483 			case (DT_BIND_NOW):
1484 				pdynitem_val("BIND_NOW", &p_dyn);
1485 				break;
1486 			case (DT_INIT_ARRAY):
1487 				pdynitem_addr("INIT_ARRAY", &p_dyn);
1488 				break;
1489 			case (DT_FINI_ARRAY):
1490 				pdynitem_addr("FINI_ARRAY", &p_dyn);
1491 				break;
1492 			case (DT_INIT_ARRAYSZ):
1493 				pdynitem_addr("INIT_ARRAYSZ", &p_dyn);
1494 				break;
1495 			case (DT_FINI_ARRAYSZ):
1496 				pdynitem_addr("FINI_ARRAYSZ", &p_dyn);
1497 				break;
1498 			case (DT_RUNPATH):
1499 				pdynitem_str("RUNPATH", &p_dyn,
1500 					elf_file, link);
1501 				break;
1502 			case (DT_FLAGS):
1503 				pdynitem_bitmask("FLAGS", &p_dyn,
1504 					dyn_dt_flags);
1505 				break;
1506 
1507 			case (DT_PREINIT_ARRAY):
1508 				pdynitem_addr("PRINIT_ARRAY", &p_dyn);
1509 				break;
1510 			case (DT_PREINIT_ARRAYSZ):
1511 				pdynitem_addr("PRINIT_ARRAYSZ", &p_dyn);
1512 				break;
1513 			/*
1514 			 * DT_LOOS - DT_HIOS range.
1515 			 */
1516 			case (DT_SUNW_AUXILIARY):
1517 				pdynitem_str("SUNW_AUXILIARY", &p_dyn,
1518 					elf_file, link);
1519 				break;
1520 			case (DT_SUNW_RTLDINF):
1521 				pdynitem_addr("SUNW_RTLDINF", &p_dyn);
1522 				break;
1523 			case (DT_SUNW_FILTER):
1524 				pdynitem_str("SUNW_FILTER", &p_dyn,
1525 					elf_file, link);
1526 				break;
1527 			case (DT_SUNW_CAP):
1528 				pdynitem_addr("SUNW_CAP", &p_dyn);
1529 				break;
1530 
1531 			/*
1532 			 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
1533 			 */
1534 			case (DT_CHECKSUM):
1535 				pdynitem_val("CHECKSUM", &p_dyn);
1536 				break;
1537 			case (DT_PLTPADSZ):
1538 				pdynitem_val("PLTPADSZ", &p_dyn);
1539 				break;
1540 			case (DT_MOVEENT):
1541 				pdynitem_val("MOVEENT", &p_dyn);
1542 				break;
1543 			case (DT_MOVESZ):
1544 				pdynitem_val("MOVESZ", &p_dyn);
1545 				break;
1546 			case (DT_FEATURE_1):
1547 				pdynitem_bitmask("FEATURE_1", &p_dyn,
1548 					dyn_dt_feature_1);
1549 				break;
1550 			case (DT_POSFLAG_1):
1551 				pdynitem_bitmask("POSFLAG_1", &p_dyn,
1552 					dyn_dt_posflag_1);
1553 				break;
1554 			case (DT_SYMINSZ):
1555 				pdynitem_val("SYMINSZ", &p_dyn);
1556 				break;
1557 			case (DT_SYMINENT):
1558 				pdynitem_val("SYMINENT", &p_dyn);
1559 				break;
1560 
1561 			/*
1562 			 * SUNW: DT_ADDRRNGLO - DT_ADDRRNGHI range.
1563 			 */
1564 			case (DT_CONFIG):
1565 				pdynitem_str("CONFIG", &p_dyn, elf_file, link);
1566 				break;
1567 			case (DT_DEPAUDIT):
1568 				pdynitem_str("DEPAUDIT", &p_dyn,
1569 					elf_file, link);
1570 				break;
1571 			case (DT_AUDIT):
1572 				pdynitem_str("AUDIT", &p_dyn, elf_file, link);
1573 				break;
1574 			case (DT_PLTPAD):
1575 				pdynitem_addr("PLTPAD", &p_dyn);
1576 				break;
1577 			case (DT_MOVETAB):
1578 				pdynitem_addr("MOVETAB", &p_dyn);
1579 				break;
1580 			case (DT_SYMINFO):
1581 				pdynitem_addr("SYMINFO", &p_dyn);
1582 				break;
1583 
1584 			/*
1585 			 * SUNW: generic range.
1586 			 */
1587 			case (DT_RELACOUNT):
1588 				pdynitem_addr("RELACOUNT", &p_dyn);
1589 				break;
1590 			case (DT_RELCOUNT):
1591 				pdynitem_addr("RELCOUNT", &p_dyn);
1592 				break;
1593 			case (DT_FLAGS_1):
1594 				pdynitem_bitmask("FLAGS_1", &p_dyn,
1595 					dyn_dt_flags_1);
1596 				break;
1597 			case (DT_VERSYM):
1598 				pdynitem_addr("VERSYM", &p_dyn);
1599 				break;
1600 			case (DT_VERDEF):
1601 				pdynitem_addr("VERDEF", &p_dyn);
1602 				break;
1603 			case (DT_VERDEFNUM):
1604 				pdynitem_addr("VERDEFNUM", &p_dyn);
1605 				break;
1606 			case (DT_VERNEED):
1607 				pdynitem_addr("VERNEED", &p_dyn);
1608 				break;
1609 			case (DT_VERNEEDNUM):
1610 				pdynitem_val("VERNEEDNUM", &p_dyn);
1611 				break;
1612 			case (DT_AUXILIARY):
1613 				pdynitem_str("AUXILIARY", &p_dyn,
1614 					elf_file, link);
1615 				break;
1616 			case (DT_USED):
1617 				pdynitem_str("USED", &p_dyn, elf_file, link);
1618 				break;
1619 			case (DT_FILTER):
1620 				pdynitem_str("FILTER", &p_dyn, elf_file, link);
1621 				break;
1622 
1623 			/*
1624 			 * SUNW: machine specific range.
1625 			 */
1626 			case (DT_SPARC_REGISTER):
1627 				pdynitem_val("REGISTER", &p_dyn);
1628 				break;
1629 			case (DT_DEPRECATED_SPARC_REGISTER):
1630 				pdynitem_depval("REGISTER", &p_dyn);
1631 				break;
1632 			default:
1633 				(void) printf("%lld", EC_XWORD(p_dyn.d_tag));
1634 				break;
1635 			}
1636 			(void) printf("\n");
1637 			(void) gelf_getdyn(dyn_data, ii++, &p_dyn);
1638 		}
1639 	}
1640 
1641 	/*
1642 	 * Check for existence of static shared library information.
1643 	 */
1644 	(void) gelf_getehdr(elf_file, &p_ehdr);
1645 	while (header_num < p_ehdr.e_phnum) {
1646 		(void) gelf_getphdr(elf_file, header_num, &p_phdr);
1647 		if (p_phdr.p_type == PT_SHLIB) {
1648 			while (--lib_scns > 0) {
1649 				if (strcmp(l_scns->scn_name, ".lib") == 0) {
1650 					print_static(l_scns, filename);
1651 				}
1652 				l_scns++;
1653 			}
1654 		}
1655 		header_num++;
1656 	}
1657 }
1658 
1659 /*
1660  * Print the ELF header.  Input is an ELF file descriptor
1661  * and the filename.  If f_flag is set, the ELF header is
1662  * printed to stdout, otherwise the function returns after
1663  * setting the pointer to the ELF header.  Any values which
1664  * are not known are printed in decimal.  Fields must be updated
1665  * as new values are added.
1666  */
1667 static GElf_Ehdr *
1668 dump_elf_header(Elf *elf_file, char *filename, GElf_Ehdr * elf_head_p)
1669 {
1670 	int class, data;
1671 	int field;
1672 
1673 	if (gelf_getehdr(elf_file, elf_head_p) == NULL) {
1674 		(void) fprintf(stderr, "%s: %s: %s\n", prog_name, filename,
1675 		    elf_errmsg(-1));
1676 		return (NULL);
1677 	}
1678 
1679 	class = (int)elf_head_p->e_ident[4];
1680 
1681 	if (class == ELFCLASS64)
1682 		field = 21;
1683 	else
1684 		field = 13;
1685 
1686 	if (!f_flag)
1687 		return (elf_head_p);
1688 
1689 	if (!p_flag) {
1690 		(void) printf("\n                    **** ELF HEADER ****\n");
1691 		(void) printf("%-*s%-11s%-*sMachine     Version\n",
1692 		    field, "Class", "Data", field, "Type");
1693 		(void) printf("%-*s%-11s%-*sFlags       Ehsize\n",
1694 		    field, "Entry", "Phoff", field, "Shoff");
1695 		(void) printf("%-*s%-11s%-*sShnum       Shstrndx\n\n",
1696 		    field, "Phentsize", "Phnum", field, "Shentsz");
1697 	}
1698 
1699 	if (!v_flag) {
1700 		(void) printf("%-*d%-11d%-*d%-12d%d\n",
1701 			field, elf_head_p->e_ident[4],
1702 			elf_head_p->e_ident[5],
1703 			field, (int)elf_head_p->e_type,
1704 			(int)elf_head_p->e_machine,
1705 			elf_head_p->e_version);
1706 	} else {
1707 		data = elf_head_p->e_ident[5];
1708 
1709 		switch (class) {
1710 		case ELFCLASSNONE:
1711 			(void) printf("%-*s", field, "None");
1712 			break;
1713 		case ELFCLASS32:
1714 			(void) printf("%-*s", field, "32-bit");
1715 			break;
1716 		case ELFCLASS64:
1717 			(void) printf("%-*s", field, "64-bit");
1718 			break;
1719 		default:
1720 			(void) printf("%-*d", field, class);
1721 			break;
1722 		}
1723 		switch (data) {
1724 		case ELFDATANONE:
1725 			(void) printf("%-11s", "None   ");
1726 			break;
1727 		case ELFDATA2LSB:
1728 			(void) printf("%-11s", "2LSB   ");
1729 			break;
1730 		case ELFDATA2MSB:
1731 			(void) printf("%-11s", "2MSB   ");
1732 			break;
1733 		default:
1734 			(void) printf("%-11d", data);
1735 			break;
1736 		}
1737 
1738 		switch (elf_head_p->e_type) {
1739 		case ET_NONE:
1740 			(void) printf("%-*s", field, "None");
1741 			break;
1742 		case ET_REL:
1743 			(void) printf("%-*s", field, "Reloc");
1744 			break;
1745 		case ET_EXEC:
1746 			(void) printf("%-*s", field, "Exec");
1747 			break;
1748 		case ET_DYN:
1749 			(void) printf("%-*s", field, "Dyn");
1750 			break;
1751 		case ET_CORE:
1752 			(void) printf("%-*s", field, "Core");
1753 			break;
1754 		default:
1755 			(void) printf("%-*d", field,
1756 				EC_WORD(elf_head_p->e_type));
1757 			break;
1758 		}
1759 		switch (elf_head_p->e_machine) {
1760 		case EM_NONE:
1761 			(void) printf("%-12s", "No mach");
1762 			break;
1763 		case EM_M32:
1764 			(void) printf("%-12s", "WE32100");
1765 			break;
1766 		case EM_SPARC:
1767 			(void) printf("%-12s", "SPARC");
1768 			break;
1769 		case EM_SPARCV9:
1770 			(void) printf("%-12s", "SPARCV9");
1771 			break;
1772 		case EM_386:
1773 			(void) printf("%-12s", "80386");
1774 			break;
1775 		case EM_68K:
1776 			(void) printf("%-12s", "68000");
1777 			break;
1778 		case EM_88K:
1779 			(void) printf("%-12s", "88000");
1780 			break;
1781 		case EM_486:
1782 			(void) printf("%-12s", "80486");
1783 			break;
1784 		case EM_860:
1785 			(void) printf("%-12s", "i860");
1786 			break;
1787 		case EM_MIPS:
1788 			(void) printf("%-12s", "RS3000_BE");
1789 			break;
1790 		case EM_MIPS_RS3_LE:
1791 			(void) printf("%-12s", "RS3000_LE");
1792 			break;
1793 		case EM_RS6000:
1794 			(void) printf("%-12s", "RS6000");
1795 			break;
1796 		case EM_PA_RISC:
1797 			(void) printf("%-12s", "PA_RISC");
1798 			break;
1799 		case EM_nCUBE:
1800 			(void) printf("%-12s", "nCUBE");
1801 			break;
1802 		case EM_VPP500:
1803 			(void) printf("%-12s", "VPP500");
1804 			break;
1805 		case EM_SPARC32PLUS:
1806 			(void) printf("%-12s", "SPARC32PLUS");
1807 			break;
1808 		case EM_PPC:
1809 			(void) printf("%-12s", "PowerPC");
1810 			break;
1811 		case EM_IA_64:
1812 			(void) printf("%-12s", "IA64");
1813 			break;
1814 		default:
1815 			(void) printf("%-12d", EC_WORD(elf_head_p->e_machine));
1816 		}
1817 		switch (elf_head_p->e_version) {
1818 		case EV_NONE:
1819 			(void) printf("Invalid\n");
1820 			break;
1821 		case EV_CURRENT:
1822 			(void) printf("Current\n");
1823 			break;
1824 		default:
1825 			(void) printf("%d\n", elf_head_p->e_version);
1826 		}
1827 	}
1828 	(void) printf("%-#*llx%-#11llx%-#*llx%-#12x%#x\n",
1829 		field, EC_ADDR(elf_head_p->e_entry),
1830 		EC_OFF(elf_head_p->e_phoff),
1831 		field, EC_OFF(elf_head_p->e_shoff),
1832 		EC_WORD(elf_head_p->e_flags),
1833 		EC_WORD(elf_head_p->e_ehsize));
1834 	if (!v_flag || (elf_head_p->e_shstrndx != SHN_XINDEX)) {
1835 		(void) printf("%-#*x%-11u%-#*x%-12u%u\n",
1836 			field, EC_WORD(elf_head_p->e_phentsize),
1837 			EC_WORD(elf_head_p->e_phnum),
1838 			field, EC_WORD(elf_head_p->e_shentsize),
1839 			EC_WORD(elf_head_p->e_shnum),
1840 			EC_WORD(elf_head_p->e_shstrndx));
1841 	} else {
1842 		(void) printf("%-#*x%-11u%-#*x%-12uXINDEX\n",
1843 			field, EC_WORD(elf_head_p->e_phentsize),
1844 			EC_WORD(elf_head_p->e_phnum),
1845 			field, EC_WORD(elf_head_p->e_shentsize),
1846 			EC_WORD(elf_head_p->e_shnum));
1847 	}
1848 	if ((elf_head_p->e_shnum == 0) && (elf_head_p->e_shoff > 0)) {
1849 		Elf_Scn		*scn;
1850 		GElf_Shdr	shdr0;
1851 		int		field;
1852 
1853 		if (gelf_getclass(elf_file) == ELFCLASS64)
1854 			field = 21;
1855 		else
1856 			field = 13;
1857 		if (!p_flag) {
1858 			(void) printf("\n	   **** SECTION HEADER[0] "
1859 			    "{Elf Extensions} ****\n");
1860 			(void) printf(
1861 			    "[No]\tType\tFlags\t%-*s %-*s%-*s%sName\n",
1862 			    field, "Addr", field, "Offset", field,
1863 			    "Size(shnum)",
1864 			    /* compatibility:  tab for elf32 */
1865 			    (field == 13) ? "\t" : "  ");
1866 			(void) printf("\tLn(strndx) Info\t%-*s Entsize\n",
1867 			    field, "Adralgn");
1868 		}
1869 		if ((scn = elf_getscn(elf_file, 0)) == NULL) {
1870 			(void) fprintf(stderr,
1871 				"%s: %s: elf_getscn failed: %s\n",
1872 				prog_name, filename, elf_errmsg(-1));
1873 			return (NULL);
1874 		}
1875 		if (gelf_getshdr(scn, &shdr0) == 0) {
1876 			(void) fprintf(stderr,
1877 				"%s: %s: gelf_getshdr: %s\n",
1878 				prog_name, filename, elf_errmsg(-1));
1879 			return (NULL);
1880 		}
1881 		(void) printf("[0]\t%u\t%llu\t", EC_WORD(shdr0.sh_type),
1882 			EC_XWORD(shdr0.sh_flags));
1883 
1884 		/*
1885 		 * LINTED - field and EC_XWORD cause -#*llu complaints that
1886 		 * even this comment can't shutup.
1887 		 */
1888 		(void) printf("%-#*llx %-#*llx%-#*llu%s%-#*u\n",
1889 			field, EC_ADDR(shdr0.sh_addr),
1890 			field, EC_OFF(shdr0.sh_offset),
1891 			field, EC_XWORD(shdr0.sh_size),
1892 			/* compatibility:  tab for elf32 */
1893 			((field == 13) ? "\t" : "  "),
1894 			field, EC_WORD(shdr0.sh_name));
1895 
1896 		(void) printf("\t%u\t%u\t%-#*llx %-#*llx\n",
1897 			EC_WORD(shdr0.sh_link),
1898 			EC_WORD(shdr0.sh_info),
1899 			field, EC_XWORD(shdr0.sh_addralign),
1900 			field, EC_XWORD(shdr0.sh_entsize));
1901 	}
1902 	(void) printf("\n");
1903 
1904 	return (elf_head_p);
1905 }
1906 
1907 /*
1908  * Print section contents.  Input is an ELF file descriptor,
1909  * the ELF header, the SCNTAB structure,
1910  * the number of symbols, and the filename.
1911  * The number of sections,
1912  * and the offset into the SCNTAB structure will be
1913  * set in dump_section if d_flag or n_flag are set.
1914  * If v_flag is set, sections which can be interpreted will
1915  * be interpreted, otherwise raw data will be output in hexidecimal.
1916  */
1917 static void
1918 print_section(Elf *elf_file,
1919 	GElf_Ehdr *p_ehdr, SCNTAB *p, int num_scns, char *filename)
1920 {
1921 	unsigned char    *p_sec;
1922 	int	i;
1923 	size_t	size;
1924 
1925 	for (i = 0; i < num_scns; i++, p++) {
1926 		GElf_Shdr shdr;
1927 
1928 		size = 0;
1929 		if (s_flag && !v_flag)
1930 			p_sec = (unsigned char *)get_rawscn(p->p_sd, &size);
1931 		else
1932 			p_sec = (unsigned char *)get_scndata(p->p_sd, &size);
1933 
1934 		if ((gelf_getshdr(p->p_sd, &shdr) != NULL) &&
1935 		    (shdr.sh_type == SHT_NOBITS)) {
1936 			continue;
1937 		}
1938 		if (s_flag && !v_flag) {
1939 			(void) printf("\n%s:\n", p->scn_name);
1940 			print_rawdata(p_sec, size);
1941 			continue;
1942 		}
1943 		if (shdr.sh_type == SHT_SYMTAB) {
1944 			dump_symbol_table(elf_file, p, filename);
1945 			continue;
1946 		}
1947 		if (shdr.sh_type == SHT_DYNSYM) {
1948 			dump_symbol_table(elf_file, p, filename);
1949 			continue;
1950 		}
1951 		if (shdr.sh_type == SHT_STRTAB) {
1952 			dump_string_table(p, 1);
1953 			continue;
1954 		}
1955 		if (shdr.sh_type == SHT_RELA) {
1956 			dump_reloc_table(elf_file, p_ehdr, p, 1, filename);
1957 			continue;
1958 		}
1959 		if (shdr.sh_type == SHT_REL) {
1960 			dump_reloc_table(elf_file, p_ehdr, p, 1, filename);
1961 			continue;
1962 		}
1963 		if (shdr.sh_type == SHT_DYNAMIC) {
1964 			dump_dynamic(elf_file, p, 1, filename);
1965 			continue;
1966 		}
1967 
1968 		(void) printf("\n%s:\n", p->scn_name);
1969 		print_rawdata(p_sec, size);
1970 	}
1971 	(void) printf("\n");
1972 }
1973 
1974 /*
1975  * Print section contents. This function does not print the contents
1976  * of the sections but sets up the parameters and then calls
1977  * print_section to print the contents.  Calling another function to print
1978  * the contents allows both -d and -n to work correctly
1979  * simultaneously. Input is an ELF file descriptor, the ELF header,
1980  * the SCNTAB structure, the number of sections, and the filename.
1981  * Set the range of sections if d_flag, and set section name if
1982  * n_flag.
1983  */
1984 static void
1985 dump_section(Elf *elf_file,
1986 	GElf_Ehdr *p_ehdr, SCNTAB *s, int num_scns, char *filename)
1987 {
1988 	SCNTAB *n_range, *d_range; /* for use with -n and -d modifiers */
1989 	int i;
1990 	int found_it = 0;  /* for use with -n section_name */
1991 
1992 	if (n_flag) {
1993 		n_range = s;
1994 
1995 		for (i = 0; i < num_scns; i++, n_range++) {
1996 			if ((strcmp(name, n_range->scn_name)) != 0)
1997 				continue;
1998 			else {
1999 				found_it = 1;
2000 				print_section(elf_file, p_ehdr,
2001 					n_range, 1, filename);
2002 			}
2003 		}
2004 
2005 		if (!found_it) {
2006 			(void) fprintf(stderr, "%s: %s: %s not found\n",
2007 				prog_name, filename, name);
2008 		}
2009 	} /* end n_flag */
2010 
2011 	if (d_flag) {
2012 		d_range = s;
2013 		d_num = check_range(d_low, d_hi, num_scns, filename);
2014 		if (d_num < 0)
2015 			return;
2016 		d_range += d_low - 1;
2017 
2018 		print_section(elf_file, p_ehdr, d_range, d_num, filename);
2019 	}	/* end d_flag */
2020 
2021 	if (!n_flag && !d_flag)
2022 		print_section(elf_file, p_ehdr, s, num_scns, filename);
2023 }
2024 
2025 /*
2026  * Print the section header table. This function does not print the contents
2027  * of the section headers but sets up the parameters and then calls
2028  * print_shdr to print the contents.  Calling another function to print
2029  * the contents allows both -d and -n to work correctly
2030  * simultaneously.  Input is the SCNTAB structure,
2031  * the number of sections from the ELF header, and the filename.
2032  * Set the range of section headers to print if d_flag, and set
2033  * name of section header to print if n_flag.
2034  */
2035 static void
2036 dump_shdr(Elf *elf_file, SCNTAB *s, int num_scns, char *filename)
2037 {
2038 
2039 	SCNTAB *n_range, *d_range;	/* for use with -n and -d modifiers */
2040 	int field;
2041 	int i;
2042 	int found_it = 0;  /* for use with -n section_name */
2043 
2044 	if (gelf_getclass(elf_file) == ELFCLASS64)
2045 		field = 21;
2046 	else
2047 		field = 13;
2048 
2049 	if (!p_flag) {
2050 		(void) printf("\n	   **** SECTION HEADER TABLE ****\n");
2051 		(void) printf("[No]\tType\tFlags\t%-*s %-*s %-*s%sName\n",
2052 		    field, "Addr", field, "Offset", field, "Size",
2053 		    /* compatibility:  tab for elf32 */
2054 		    (field == 13) ? "\t" : "  ");
2055 		(void) printf("\tLink\tInfo\t%-*s Entsize\n\n",
2056 		    field, "Adralgn");
2057 	}
2058 
2059 	if (n_flag) {
2060 		n_range = s;
2061 
2062 		for (i = 1; i <= num_scns; i++, n_range++) {
2063 			if ((strcmp(name, n_range->scn_name)) != 0)
2064 				continue;
2065 			else {
2066 				found_it = 1;
2067 				print_shdr(elf_file, n_range, 1, i);
2068 			}
2069 		}
2070 
2071 		if (!found_it) {
2072 			(void) fprintf(stderr, "%s: %s: %s not found\n",
2073 				prog_name, filename, name);
2074 		}
2075 	} /* end n_flag */
2076 
2077 	if (d_flag) {
2078 		d_range = s;
2079 		d_num = check_range(d_low, d_hi, num_scns, filename);
2080 		if (d_num < 0)
2081 			return;
2082 		d_range += d_low - 1;
2083 
2084 		print_shdr(elf_file, d_range, d_num, d_low);
2085 	}	/* end d_flag */
2086 
2087 	if (!n_flag && !d_flag)
2088 		print_shdr(elf_file, s, num_scns, 1);
2089 }
2090 
2091 /*
2092  * Process all of the command line options (except
2093  * for -a, -g, -f, and -o).  All of the options processed
2094  * by this function require the presence of the section
2095  * header table and will not be processed if it is not present.
2096  * Set up a buffer containing section name, section header,
2097  * and section descriptor for each section in the file.  This
2098  * structure is used to avoid duplicate calls to libelf functions.
2099  * Structure members for the symbol table, the debugging information,
2100  * and the line number information are global.  All of the
2101  * rest are local.
2102  */
2103 static void
2104 dump_section_table(Elf *elf_file, GElf_Ehdr *elf_head_p, char *filename)
2105 {
2106 
2107 	static SCNTAB	*buffer, *p_scns;
2108 	Elf_Scn		*scn = 0;
2109 	char		*s_name = NULL;
2110 	int		found = 0;
2111 	unsigned int	num_scns;
2112 	size_t		shstrndx;
2113 	size_t		shnum;
2114 
2115 
2116 	if (elf_getshnum(elf_file, &shnum) == 0) {
2117 		(void) fprintf(stderr,
2118 			"%s: %s: elf_getshnum failed: %s\n",
2119 			prog_name, filename, elf_errmsg(-1));
2120 		return;
2121 	}
2122 	if (elf_getshstrndx(elf_file, &shstrndx) == 0) {
2123 		(void) fprintf(stderr,
2124 			"%s: %s: elf_getshstrndx failed: %s\n",
2125 			prog_name, filename, elf_errmsg(-1));
2126 		return;
2127 	}
2128 
2129 	if ((buffer = calloc(shnum, sizeof (SCNTAB))) == NULL) {
2130 		(void) fprintf(stderr, "%s: %s: cannot calloc space\n",
2131 			prog_name, filename);
2132 		return;
2133 	}
2134 	/* LINTED */
2135 	num_scns = (int)shnum - 1;
2136 
2137 	p_symtab = (SCNTAB *)0;
2138 	p_dynsym = (SCNTAB *)0;
2139 	p_scns = buffer;
2140 	p_head_scns = buffer;
2141 
2142 	while ((scn = elf_nextscn(elf_file, scn)) != 0) {
2143 		if ((gelf_getshdr(scn, &buffer->p_shdr)) == 0) {
2144 			(void) fprintf(stderr,
2145 			"%s: %s: %s\n", prog_name, filename, elf_errmsg(-1));
2146 			return;
2147 		}
2148 		s_name = (char *)elf_strptr(elf_file,
2149 			shstrndx, buffer->p_shdr.sh_name);
2150 		buffer->scn_name = s_name ? s_name : (char *)UNKNOWN;
2151 		buffer->p_sd   =  scn;
2152 
2153 		if (buffer->p_shdr.sh_type == SHT_SYMTAB) {
2154 			found += 1;
2155 			p_symtab = buffer;
2156 		}
2157 		if (buffer->p_shdr.sh_type == SHT_DYNSYM)
2158 			p_dynsym = buffer;
2159 		buffer++;
2160 	}
2161 
2162 	/*
2163 	 * These functions depend upon the presence of the section header table
2164 	 * and will not be invoked in its absence
2165 	 */
2166 	if (h_flag) {
2167 		dump_shdr(elf_file, p_scns, num_scns, filename);
2168 	}
2169 	if (p_symtab && (t_flag || T_flag)) {
2170 		dump_symbol_table(elf_file, p_symtab, filename);
2171 	}
2172 	if (c_flag) {
2173 		dump_string_table(p_scns, num_scns);
2174 	}
2175 	if (r_flag) {
2176 		dump_reloc_table(elf_file, elf_head_p,
2177 			p_scns, num_scns, filename);
2178 	}
2179 	if (L_flag) {
2180 		dump_dynamic(elf_file, p_scns, num_scns, filename);
2181 	}
2182 	if (s_flag) {
2183 		dump_section(elf_file, elf_head_p, p_scns,
2184 			num_scns, filename);
2185 	}
2186 }
2187 
2188 /*
2189  * Load the archive string table(s) (for extended-length strings)
2190  * into an in-core table/list
2191  */
2192 static struct stab_list_s *
2193 load_arstring_table(struct stab_list_s *STabList,
2194 	int fd, Elf *elf_file, Elf_Arhdr *p_ar, char *filename)
2195 {
2196 	off_t here;
2197 	struct stab_list_s *STL_entry, *STL_next;
2198 
2199 	if (p_ar) {
2200 		STL_entry = malloc(sizeof (struct stab_list_s));
2201 		STL_entry->next    = 0;
2202 		STL_entry->strings = 0;
2203 		STL_entry->size    = 0;
2204 
2205 		if (!STabList)
2206 			STabList = STL_entry;
2207 		else {
2208 			STL_next = STabList;
2209 			while (STL_next->next != (void *)0)
2210 				STL_next = STL_next->next;
2211 			STL_next->next = STL_entry;
2212 		}
2213 
2214 		STL_entry->size    = p_ar->ar_size;
2215 		STL_entry->strings = malloc(p_ar->ar_size);
2216 		here = elf_getbase(elf_file);
2217 		if ((lseek(fd, here, 0)) != here) {
2218 			(void) fprintf(stderr,
2219 			"%s: %s: could not lseek\n", prog_name, filename);
2220 		}
2221 
2222 		if ((read(fd, STL_entry->strings, p_ar->ar_size)) == -1) {
2223 			(void) fprintf(stderr,
2224 			"%s: %s: could not read\n", prog_name, filename);
2225 		}
2226 	}
2227 	return (STabList);
2228 }
2229 
2230 /*
2231  * Print the archive header for each member of an archive.
2232  * Also call ar_sym_read to print the symbols in the
2233  * archive symbol table if g_flag.  Input is a file descriptor,
2234  * an ELF file descriptor, and the filename.  Putting the call
2235  * to dump the archive symbol table in this function is more
2236  * efficient since it is necessary to examine the archive member
2237  * name in the archive header to determine which member is the
2238  * symbol table.
2239  */
2240 static void
2241 dump_ar_hdr(int fd, Elf *elf_file, char *filename)
2242 {
2243 	extern int v_flag, g_flag, a_flag, p_flag;
2244 	Elf_Arhdr  *p_ar;
2245 	Elf *arf;
2246 	Elf_Cmd cmd;
2247 	int title = 0;
2248 	int err = 0;
2249 
2250 	char buf[DATESIZE];
2251 
2252 	cmd = ELF_C_READ;
2253 	while ((arf = elf_begin(fd, cmd, elf_file)) != 0) {
2254 		p_ar = elf_getarhdr(arf);
2255 		if (p_ar == NULL) {
2256 			(void) fprintf(stderr,
2257 			"%s: %s: %s\n", prog_name, filename, elf_errmsg(-1));
2258 			continue;
2259 		}
2260 		if (strcmp(p_ar->ar_name, "/") == 0) {
2261 			if (g_flag)
2262 				ar_sym_read(elf_file, filename);
2263 		} else if (strcmp(p_ar->ar_name, "//") == 0) {
2264 			StringTableList = load_arstring_table(
2265 				StringTableList, fd, arf, p_ar,
2266 				filename);
2267 			cmd = elf_next(arf);
2268 			(void) elf_end(arf);
2269 			continue;
2270 		} else {
2271 			if (a_flag) {
2272 				(void) printf("%s[%s]:\n", filename,
2273 					p_ar->ar_name);
2274 				if (!p_flag && title == 0) {
2275 					if (!v_flag)
2276 						(void) printf(
2277 "\n\n\t\t\t***ARCHIVE HEADER***"
2278 "\n	Date          Uid     Gid    Mode      Size	 Member Name\n\n");
2279 					else
2280 						(void) printf(
2281 "\n\n\t\t\t***ARCHIVE HEADER***"
2282 "\n	Date                   Uid    Gid   Mode     Size     Member Name\n\n");
2283 					title = 1;
2284 				}
2285 				if (!v_flag) {
2286 					(void) printf(
2287 "\t0x%.8lx  %6d  %6d  0%.6ho  0x%.8lx  %-s\n\n",
2288 						p_ar->ar_date,
2289 						(int)p_ar->ar_uid,
2290 						(int)p_ar->ar_gid,
2291 						(int)p_ar->ar_mode,
2292 						p_ar->ar_size,
2293 						p_ar->ar_name);
2294 				} else {
2295 					if ((strftime(buf, DATESIZE,
2296 					    "%b %d %H:%M:%S %Y",
2297 					    localtime(
2298 					    &(p_ar->ar_date)))) == 0) {
2299 						(void) fprintf(stderr,
2300 "%s: %s: don't have enough space to store the date\n", prog_name, filename);
2301 						exit(1);
2302 					}
2303 					(void) printf(
2304 					"\t%s %6d %6d 0%.6ho 0x%.8lx %-s\n\n",
2305 						buf,
2306 						(int)p_ar->ar_uid,
2307 						(int)p_ar->ar_gid,
2308 						(int)p_ar->ar_mode,
2309 						p_ar->ar_size,
2310 						p_ar->ar_name);
2311 				}
2312 			}
2313 		}
2314 		cmd = elf_next(arf);
2315 		(void) elf_end(arf);
2316 	} /* end while */
2317 
2318 	err = elf_errno();
2319 	if (err != 0) {
2320 		(void) fprintf(stderr,
2321 		"%s: %s: %s\n", prog_name, filename, elf_errmsg(err));
2322 	}
2323 }
2324 
2325 /*
2326  * Process member files of an archive.  This function provides
2327  * a loop through an archive equivalent the processing of
2328  * each_file for individual object files.
2329  */
2330 static void
2331 dump_ar_files(int fd, Elf *elf_file, char *filename)
2332 {
2333 	Elf_Arhdr  *p_ar;
2334 	Elf *arf;
2335 	Elf_Cmd cmd;
2336 	Elf_Kind file_type;
2337 	GElf_Ehdr elf_head;
2338 	char *fullname;
2339 
2340 	cmd = ELF_C_READ;
2341 	while ((arf = elf_begin(fd, cmd, elf_file)) != 0) {
2342 		size_t	len;
2343 
2344 		p_ar = elf_getarhdr(arf);
2345 		if (p_ar == NULL) {
2346 			(void) fprintf(stderr,
2347 				"%s: %s: %s\n",
2348 				prog_name, filename, elf_errmsg(-1));
2349 			return;
2350 		}
2351 		if ((strcmp(p_ar->ar_name, "/") == 0) ||
2352 			(strcmp(p_ar->ar_name, "//") == 0)) {
2353 			cmd = elf_next(arf);
2354 			(void) elf_end(arf);
2355 			continue;
2356 		}
2357 
2358 		len = strlen(filename) + strlen(p_ar->ar_name) + 3;
2359 		if ((fullname = malloc(len)) == NULL)
2360 			return;
2361 		(void) snprintf(fullname, len, "%s[%s]", filename,
2362 		    p_ar->ar_name);
2363 		(void) printf("\n%s:\n", fullname);
2364 		file_type = elf_kind(arf);
2365 		if (file_type == ELF_K_ELF) {
2366 			if (dump_elf_header(arf, fullname, &elf_head) == NULL)
2367 				return;
2368 			if (o_flag)
2369 				dump_exec_header(arf,
2370 					(unsigned)elf_head.e_phnum, fullname);
2371 			if (x_flag)
2372 				dump_section_table(arf, &elf_head, fullname);
2373 		} else {
2374 			(void) fprintf(stderr,
2375 				"%s: %s: invalid file type\n",
2376 				prog_name, fullname);
2377 			cmd = elf_next(arf);
2378 			(void) elf_end(arf);
2379 			continue;
2380 		}
2381 
2382 		cmd = elf_next(arf);
2383 		(void) elf_end(arf);
2384 	} /* end while */
2385 }
2386 
2387 /*
2388  * Takes a filename as input.  Test first for a valid version
2389  * of libelf.a and exit on error.  Process each valid file
2390  * or archive given as input on the command line.  Check
2391  * for file type.  If it is an archive, process the archive-
2392  * specific options first, then files within the archive.
2393  * If it is an ELF object file, process it; otherwise
2394  * warn that it is an invalid file type.
2395  * All options except the archive-specific and program
2396  * execution header are processed in the function, dump_section_table.
2397  */
2398 static void
2399 each_file(char *filename)
2400 {
2401 	Elf *elf_file;
2402 	GElf_Ehdr elf_head;
2403 	int fd;
2404 	Elf_Kind   file_type;
2405 
2406 	struct stat buf;
2407 
2408 	Elf_Cmd cmd;
2409 	errno = 0;
2410 
2411 	if (stat(filename, &buf) == -1) {
2412 		int	err = errno;
2413 		(void) fprintf(stderr, "%s: %s: %s", prog_name, filename,
2414 		    strerror(err));
2415 		return;
2416 	}
2417 
2418 	if ((fd = open((filename), O_RDONLY)) == -1) {
2419 		(void) fprintf(stderr, "%s: %s: cannot read\n", prog_name,
2420 		    filename);
2421 		return;
2422 	}
2423 	cmd = ELF_C_READ;
2424 	if ((elf_file = elf_begin(fd, cmd, (Elf *)0)) == NULL) {
2425 		(void) fprintf(stderr, "%s: %s: %s\n", prog_name, filename,
2426 		    elf_errmsg(-1));
2427 		return;
2428 	}
2429 
2430 	file_type = elf_kind(elf_file);
2431 	if (file_type == ELF_K_AR) {
2432 		if (a_flag || g_flag) {
2433 			dump_ar_hdr(fd, elf_file, filename);
2434 			elf_file = elf_begin(fd, cmd, (Elf *)0);
2435 		}
2436 		if (z_flag)
2437 			dump_ar_files(fd, elf_file, filename);
2438 	} else {
2439 		if (file_type == ELF_K_ELF) {
2440 			(void) printf("\n%s:\n", filename);
2441 			if (dump_elf_header(elf_file, filename, &elf_head)) {
2442 				if (o_flag)
2443 					dump_exec_header(elf_file,
2444 					    (unsigned)elf_head.e_phnum,
2445 					    filename);
2446 				if (x_flag)
2447 					dump_section_table(elf_file,
2448 					    &elf_head, filename);
2449 			}
2450 		} else {
2451 			(void) fprintf(stderr, "%s: %s: invalid file type\n",
2452 			    prog_name, filename);
2453 		}
2454 	}
2455 	(void) elf_end(elf_file);
2456 	(void) close(fd);
2457 }
2458 
2459 /*
2460  * Sets up flags for command line options given and then
2461  * calls each_file() to process each file.
2462  */
2463 int
2464 main(int argc, char *argv[], char *envp[])
2465 {
2466 	char *optstr = OPTSTR; /* option string used by getopt() */
2467 	int optchar;
2468 
2469 	/*
2470 	 * Check for a binary that better fits this architecture.
2471 	 */
2472 	conv_check_native(argv, envp);
2473 
2474 	prog_name = argv[0];
2475 
2476 	(void) setlocale(LC_ALL, "");
2477 	while ((optchar = getopt(argc, argv, optstr)) != -1) {
2478 		switch (optchar) {
2479 		case 'a':
2480 			a_flag = 1;
2481 			x_flag = 1;
2482 			break;
2483 		case 'g':
2484 			g_flag = 1;
2485 			x_flag = 1;
2486 			break;
2487 		case 'v':
2488 			v_flag = 1;
2489 			break;
2490 		case 'p':
2491 			p_flag = 1;
2492 			break;
2493 		case 'f':
2494 			f_flag = 1;
2495 			z_flag = 1;
2496 			break;
2497 		case 'o':
2498 			o_flag = 1;
2499 			z_flag = 1;
2500 			break;
2501 		case 'h':
2502 			h_flag = 1;
2503 			x_flag = 1;
2504 			z_flag = 1;
2505 			break;
2506 		case 's':
2507 			s_flag = 1;
2508 			x_flag = 1;
2509 			z_flag = 1;
2510 			break;
2511 		case 'd':
2512 			d_flag = 1;
2513 			x_flag = 1;
2514 			z_flag = 1;
2515 			set_range(optarg, &d_low, &d_hi);
2516 			break;
2517 		case 'n':
2518 			n_flag++;
2519 			x_flag = 1;
2520 			z_flag = 1;
2521 			name = optarg;
2522 			break;
2523 		case 'r':
2524 			r_flag = 1;
2525 			x_flag = 1;
2526 			z_flag = 1;
2527 			break;
2528 		case 't':
2529 			t_flag = 1;
2530 			x_flag = 1;
2531 			z_flag = 1;
2532 			break;
2533 		case 'C':
2534 			C_flag = 1;
2535 			t_flag = 1;
2536 			x_flag = 1;
2537 			z_flag = 1;
2538 			break;
2539 		case 'T':
2540 			T_flag = 1;
2541 			x_flag = 1;
2542 			z_flag = 1;
2543 			set_range(optarg, &T_low, &T_hi);
2544 			break;
2545 		case 'c':
2546 			c_flag = 1;
2547 			x_flag = 1;
2548 			z_flag = 1;
2549 			break;
2550 		case 'L':
2551 			L_flag = 1;
2552 			x_flag = 1;
2553 			z_flag = 1;
2554 			break;
2555 		case 'V':
2556 			V_flag = 1;
2557 			(void) fprintf(stderr, "dump: %s %s\n",
2558 			    (const char *)SGU_PKG,
2559 			    (const char *)SGU_REL);
2560 			break;
2561 		case '?':
2562 			errflag += 1;
2563 			break;
2564 		default:
2565 			break;
2566 		}
2567 	}
2568 
2569 	if (errflag || (optind >= argc) || (!z_flag && !x_flag)) {
2570 		if (!(V_flag && (argc == 2))) {
2571 			usage();
2572 			exit(269);
2573 		}
2574 	}
2575 
2576 	if (elf_version(EV_CURRENT) == EV_NONE) {
2577 		(void) fprintf(stderr, "%s: libelf is out of date\n",
2578 		    prog_name);
2579 		exit(101);
2580 	}
2581 
2582 	while (optind < argc) {
2583 		each_file(argv[optind]);
2584 		optind++;
2585 	}
2586 	return (0);
2587 }
2588