dump.c revision 1618:8c9a4f31d225
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
54const char *UNKNOWN = "<unknown>";
55
56static SCNTAB *p_symtab, *p_head_scns, *p_dynsym;
57
58static 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
63static 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
81int	p_flag = 0,	/* suppress printing of headings */
82	v_flag = 0;	/* print information in verbose form */
83
84static int
85	d_low = 0,	/* range for use with -d */
86	d_hi = 0,
87	d_num = 0;
88
89static int
90	T_low = 0,	/* range for use with -T */
91	T_hi = 0,
92	T_num = 0;
93
94static char *name = NULL; /* for use with -n option */
95char *prog_name;
96static int errflag = 0;
97
98static struct stab_list_s {
99	struct stab_list_s *next;
100	char *strings;
101	size_t size;
102} *StringTableList = (void *)0;
103
104extern void ar_sym_read();
105extern 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 */
112void *
113get_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 */
130static void *
131get_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 */
150static void
151usage()
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 */
185static void
186set_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 */
213static void
214print_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 */
250static void
251print_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 */
285static void
286print_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 */
384static void
385print_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 */
469static char *
470demangled_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 */
507static void
508print_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 */
705static void
706print_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 */
855static int
856check_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 */
895static void
896dump_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 */
1042static void
1043dump_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 */
1108static void
1109dump_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 * Print dynamic linking information.  Input is an ELF
1201 * file descriptor, the SCNTAB structure, the number of
1202 * sections, and the filename.
1203 */
1204static void
1205dump_dynamic(Elf *elf_file, SCNTAB *p_scns, int num_scns, char *filename)
1206{
1207	Elf_Data	*dyn_data;
1208	GElf_Dyn	p_dyn;
1209	GElf_Phdr	p_phdr;
1210	GElf_Ehdr	p_ehdr;
1211	char		*dt_name;
1212	int		index = 1;
1213	int		lib_scns = num_scns;
1214	SCNTAB		*l_scns = p_scns;
1215	int		header_num = 0;
1216#define	Fmttag		"%-15.15s "
1217#define	Fmtptr		"%#llx"
1218
1219	if (!p_flag)
1220		(void) printf("\n  **** DYNAMIC SECTION INFORMATION ****\n");
1221
1222	for (; num_scns > 0; num_scns--, p_scns++) {
1223		GElf_Word	link;
1224		int		ii;
1225
1226
1227		if (p_scns->p_shdr.sh_type != SHT_DYNAMIC)
1228			continue;
1229
1230		if (!p_flag) {
1231			(void) printf("%s:\n", p_scns->scn_name);
1232			(void) printf("[INDEX]\tTag         Value\n");
1233		}
1234
1235		if ((dyn_data = elf_getdata(p_scns->p_sd, NULL)) == 0) {
1236			(void) fprintf(stderr, "%s: %s: no data in "
1237			    "%s section\n", prog_name, filename,
1238			    p_scns->scn_name);
1239			return;
1240		}
1241
1242		link = p_scns->p_shdr.sh_link;
1243		ii = 0;
1244
1245		(void) gelf_getdyn(dyn_data, ii++, &p_dyn);
1246		while (p_dyn.d_tag != DT_NULL) {
1247			char	value[256];
1248
1249			(void) printf("[%d]\t", index++);
1250
1251			switch (p_dyn.d_tag) {
1252			/*
1253			 * Start of generic flags.
1254			 */
1255			case (DT_NEEDED):
1256				(void) printf(Fmttag, (const char *)"NEEDED");
1257				if (v_flag)
1258					dt_name = (char *)elf_strptr(elf_file,
1259					    link, p_dyn.d_un.d_ptr);
1260				if (dt_name == NULL)
1261					dt_name = (char *)UNKNOWN;
1262				if (v_flag && strlen(dt_name))
1263					(void) printf("%s", dt_name);
1264				else
1265					(void) printf(Fmtptr,
1266					    EC_ADDR(p_dyn.d_un.d_ptr));
1267				break;
1268			case (DT_PLTRELSZ):
1269				(void) printf(Fmttag, (const char *)"PLTSZ");
1270				(void) printf(Fmtptr,
1271					EC_XWORD(p_dyn.d_un.d_val));
1272				break;
1273			case (DT_PLTGOT):
1274				(void) printf(Fmttag, (const char *)"PLTGOT");
1275				(void) printf(Fmtptr,
1276					EC_ADDR(p_dyn.d_un.d_ptr));
1277				break;
1278			case (DT_HASH):
1279				(void) printf(Fmttag, (const char *)"HASH");
1280				(void) printf(Fmtptr,
1281					EC_ADDR(p_dyn.d_un.d_ptr));
1282				break;
1283			case (DT_STRTAB):
1284				(void) printf(Fmttag, (const char *)"STRTAB");
1285				(void) printf(Fmtptr,
1286					EC_ADDR(p_dyn.d_un.d_ptr));
1287				break;
1288			case (DT_SYMTAB):
1289				(void) printf(Fmttag, (const char *)"SYMTAB");
1290				(void) printf(Fmtptr,
1291					EC_ADDR(p_dyn.d_un.d_ptr));
1292				break;
1293			case (DT_RELA):
1294				(void) printf(Fmttag, (const char *)"RELA");
1295				(void) printf(Fmtptr,
1296					EC_ADDR(p_dyn.d_un.d_ptr));
1297				break;
1298			case (DT_RELASZ):
1299				(void) printf(Fmttag, (const char *)"RELASZ");
1300				(void) printf(Fmtptr,
1301					EC_XWORD(p_dyn.d_un.d_val));
1302				break;
1303			case (DT_RELAENT):
1304				(void) printf(Fmttag, (const char *)"RELAENT");
1305				(void) printf(Fmtptr,
1306					EC_XWORD(p_dyn.d_un.d_val));
1307				break;
1308			case (DT_STRSZ):
1309				(void) printf(Fmttag, (const char *)"STRSZ");
1310				(void) printf(Fmtptr,
1311					EC_XWORD(p_dyn.d_un.d_val));
1312				break;
1313			case (DT_SYMENT):
1314				(void) printf(Fmttag, (const char *)"SYMENT");
1315				(void) printf(Fmtptr,
1316					EC_XWORD(p_dyn.d_un.d_val));
1317				break;
1318			case (DT_INIT):
1319				(void) printf(Fmttag, (const char *)"INIT");
1320				(void) printf(Fmtptr,
1321					EC_ADDR(p_dyn.d_un.d_ptr));
1322				break;
1323			case (DT_FINI):
1324				(void) printf(Fmttag, (const char *)"FINI");
1325				(void) printf(Fmtptr,
1326					EC_ADDR(p_dyn.d_un.d_ptr));
1327				break;
1328			case (DT_SONAME):
1329				(void) printf(Fmttag, (const char *)"SONAME");
1330				if (v_flag)
1331					dt_name = (char *)elf_strptr(elf_file,
1332					    link, p_dyn.d_un.d_ptr);
1333				if (dt_name == NULL)
1334					dt_name = (char *)UNKNOWN;
1335				if (v_flag && strlen(dt_name))
1336					(void) printf("%s", dt_name);
1337				else
1338					(void) printf(Fmtptr,
1339						EC_ADDR(p_dyn.d_un.d_ptr));
1340				break;
1341			case (DT_RPATH):
1342				(void) printf(Fmttag, (const char *)"RPATH");
1343				if (v_flag)
1344					dt_name = (char *)elf_strptr(elf_file,
1345					    link, p_dyn.d_un.d_ptr);
1346				if (dt_name == NULL)
1347					dt_name = (char *)UNKNOWN;
1348				if (v_flag && strlen(dt_name))
1349					(void) printf("%s", dt_name);
1350				else
1351					(void) printf(Fmtptr,
1352						EC_ADDR(p_dyn.d_un.d_ptr));
1353				break;
1354			case (DT_SYMBOLIC):
1355				(void) printf(Fmttag, (const char *)"SYMB");
1356				(void) printf("%s", (const char *)"(ignored)");
1357				break;
1358			case (DT_REL):
1359				(void) printf(Fmttag, (const char *)"REL");
1360				(void) printf(Fmtptr,
1361					EC_ADDR(p_dyn.d_un.d_ptr));
1362				break;
1363			case (DT_RELSZ):
1364				(void) printf(Fmttag, (const char *)"RELSZ");
1365				(void) printf(Fmtptr,
1366					EC_XWORD(p_dyn.d_un.d_val));
1367				break;
1368			case (DT_RELENT):
1369				(void) printf(Fmttag, (const char *)"RELENT");
1370				(void) printf(Fmtptr,
1371					EC_XWORD(p_dyn.d_un.d_val));
1372				break;
1373			case (DT_PLTREL):
1374				(void) printf(Fmttag, (const char *)"PLTREL");
1375				(void) printf(Fmtptr,
1376					EC_XWORD(p_dyn.d_un.d_val));
1377				break;
1378			case (DT_DEBUG):
1379				(void) printf(Fmttag, (const char *)"DEBUG");
1380				(void) printf(Fmtptr,
1381					EC_ADDR(p_dyn.d_un.d_ptr));
1382				break;
1383			case (DT_TEXTREL):
1384				(void) printf(Fmttag, (const char *)"TEXTREL");
1385				(void) printf(Fmtptr,
1386					EC_ADDR(p_dyn.d_un.d_val));
1387				break;
1388			case (DT_JMPREL):
1389				(void) printf(Fmttag, (const char *)"JMPREL");
1390				(void) printf(Fmtptr,
1391					EC_ADDR(p_dyn.d_un.d_ptr));
1392				break;
1393			case (DT_BIND_NOW):
1394				(void) printf(Fmttag, (const char *)"BIND_NOW");
1395				(void) printf(Fmtptr,
1396					EC_ADDR(p_dyn.d_un.d_val));
1397				break;
1398			case (DT_INIT_ARRAY):
1399				(void) printf(Fmttag,
1400					(const char *)"INIT_ARRAY");
1401				(void) printf(Fmtptr,
1402					EC_ADDR(p_dyn.d_un.d_ptr));
1403				break;
1404			case (DT_FINI_ARRAY):
1405				(void) printf(Fmttag,
1406					(const char *)"FINI_ARRAY");
1407				(void) printf(Fmtptr,
1408					EC_ADDR(p_dyn.d_un.d_ptr));
1409				break;
1410			case (DT_INIT_ARRAYSZ):
1411				(void) printf(Fmttag,
1412					(const char *)"INIT_ARRAYSZ");
1413				(void) printf(Fmtptr,
1414					EC_ADDR(p_dyn.d_un.d_ptr));
1415				break;
1416			case (DT_FINI_ARRAYSZ):
1417				(void) printf(Fmttag,
1418					(const char *)"FINI_ARRAYSZ");
1419				(void) printf(Fmtptr,
1420					EC_ADDR(p_dyn.d_un.d_ptr));
1421				break;
1422			case (DT_RUNPATH):
1423				(void) printf(Fmttag, (const char *)"RUNPATH");
1424				if (v_flag)
1425					dt_name = (char *)elf_strptr(elf_file,
1426					    link, p_dyn.d_un.d_ptr);
1427				if (dt_name == NULL)
1428					dt_name = (char *)UNKNOWN;
1429				if (v_flag && strlen(dt_name))
1430					(void) printf("%s", dt_name);
1431				else
1432					(void) printf(Fmtptr,
1433						EC_ADDR(p_dyn.d_un.d_ptr));
1434				break;
1435			case (DT_FLAGS):
1436				(void) printf(Fmttag,
1437				    (const char *)"FLAGS");
1438				value[0] = '\0';
1439				if (v_flag) {
1440					if (p_dyn.d_un.d_val & DF_ORIGIN)
1441					    (void) strcat(value,
1442						(const char *)"ORIGIN ");
1443					if (p_dyn.d_un.d_val & DF_SYMBOLIC)
1444					    (void) strcat(value,
1445						(const char *)"SYMBOLIC ");
1446					if (p_dyn.d_un.d_val & DF_TEXTREL)
1447					    (void) strcat(value,
1448						(const char *)"TEXTREL ");
1449					if (p_dyn.d_un.d_val & DF_BIND_NOW)
1450					    (void) strcat(value,
1451						(const char *)"BIND_NOW ");
1452					if (p_dyn.d_un.d_val & DF_STATIC_TLS)
1453					    (void) strcat(value,
1454						(const char *)"STATIC_TLS ");
1455				}
1456				if (v_flag && strlen(value))
1457					(void) printf("%s", value);
1458				else
1459					(void) printf(Fmtptr,
1460						EC_ADDR(p_dyn.d_un.d_ptr));
1461				break;
1462			case (DT_PREINIT_ARRAY):
1463				(void) printf(Fmttag,
1464					(const char *)"PRINIT_ARRAY");
1465				(void) printf(Fmtptr,
1466					EC_ADDR(p_dyn.d_un.d_ptr));
1467				break;
1468			case (DT_PREINIT_ARRAYSZ):
1469				(void) printf(Fmttag,
1470					(const char *)"PRINIT_ARRAYSZ");
1471				(void) printf(Fmtptr,
1472					EC_ADDR(p_dyn.d_un.d_ptr));
1473				break;
1474			/*
1475			 * DT_LOOS - DT_HIOS range.
1476			 */
1477			case (DT_SUNW_AUXILIARY):
1478				(void) printf(Fmttag,
1479					(const char *)"SUNW_AUXILIARY");
1480				if (v_flag)
1481					dt_name = (char *)elf_strptr(elf_file,
1482					    link, p_dyn.d_un.d_ptr);
1483				if (dt_name == NULL)
1484					dt_name = (char *)UNKNOWN;
1485				if (v_flag && strlen(dt_name))
1486					(void) printf("%s", dt_name);
1487				else
1488					(void) printf(Fmtptr,
1489						EC_ADDR(p_dyn.d_un.d_ptr));
1490				break;
1491			case (DT_SUNW_RTLDINF):
1492				(void) printf(Fmttag,
1493					(const char *)"SUNW_RTLDINF");
1494				(void) printf(Fmtptr,
1495					EC_ADDR(p_dyn.d_un.d_ptr));
1496				break;
1497			case (DT_SUNW_FILTER):
1498				(void) printf(Fmttag,
1499					(const char *)"SUNW_FILTER");
1500				if (v_flag)
1501					dt_name = (char *)elf_strptr(elf_file,
1502					    link, p_dyn.d_un.d_ptr);
1503				if (dt_name == NULL)
1504					dt_name = (char *)UNKNOWN;
1505				if (v_flag && strlen(dt_name))
1506					(void) printf("%s", dt_name);
1507				else
1508					(void) printf(Fmtptr,
1509						EC_ADDR(p_dyn.d_un.d_ptr));
1510				break;
1511			case (DT_SUNW_CAP):
1512				(void) printf(Fmttag,
1513					(const char *)"SUNW_CAP");
1514				(void) printf(Fmtptr,
1515					EC_ADDR(p_dyn.d_un.d_ptr));
1516				break;
1517
1518			/*
1519			 * SUNW: DT_VALRNGLO - DT_VALRNGHI range.
1520			 */
1521			case (DT_CHECKSUM):
1522				(void) printf(Fmttag,
1523					(const char *)"CHECKSUM");
1524				(void) printf(Fmtptr,
1525					EC_XWORD(p_dyn.d_un.d_val));
1526				break;
1527			case (DT_PLTPADSZ):
1528				(void) printf(Fmttag,
1529					(const char *)"PLTPADSZ");
1530				(void) printf(Fmtptr,
1531					EC_XWORD(p_dyn.d_un.d_val));
1532				break;
1533			case (DT_MOVEENT):
1534				(void) printf(Fmttag,
1535					(const char *)"MOVEENT");
1536				(void) printf(Fmtptr,
1537					EC_XWORD(p_dyn.d_un.d_val));
1538				break;
1539			case (DT_MOVESZ):
1540				(void) printf(Fmttag,
1541					(const char *)"MOVESZ");
1542				(void) printf(Fmtptr,
1543					EC_XWORD(p_dyn.d_un.d_val));
1544				break;
1545			case (DT_FEATURE_1):
1546				(void) printf(Fmttag,
1547					(const char *)"FEATURE_1");
1548				value[0] = '\0';
1549				if (v_flag) {
1550					if (p_dyn.d_un.d_val & DTF_1_PARINIT)
1551					    (void) strcat(value,
1552						(const char *)"PARINIT ");
1553					if (p_dyn.d_un.d_val & DTF_1_CONFEXP)
1554					    (void) strcat(value,
1555						(const char *)"CONFEXP ");
1556				}
1557				if (v_flag && strlen(value))
1558					(void) printf("%s", value);
1559				else
1560					(void) printf(Fmtptr,
1561						EC_ADDR(p_dyn.d_un.d_ptr));
1562				break;
1563			case (DT_POSFLAG_1):
1564				(void) printf(Fmttag,
1565					(const char *)"POSFLAG_1");
1566				value[0] = '\0';
1567				if (v_flag) {
1568					if (p_dyn.d_un.d_val & DF_P1_LAZYLOAD)
1569					    (void) strcat(value,
1570						(const char *)"LAZYLOAD ");
1571					if (p_dyn.d_un.d_val & DF_P1_GROUPPERM)
1572					    (void) strcat(value,
1573						(const char *)"GROUPPERM ");
1574				}
1575				if (v_flag && strlen(value))
1576					(void) printf("%s", value);
1577				else
1578					(void) printf(Fmtptr,
1579						EC_ADDR(p_dyn.d_un.d_ptr));
1580				break;
1581			case (DT_SYMINSZ):
1582				(void) printf(Fmttag,
1583					(const char *)"SYMINSZ");
1584				(void) printf(Fmtptr,
1585					EC_XWORD(p_dyn.d_un.d_val));
1586				break;
1587			case (DT_SYMINENT):
1588				(void) printf(Fmttag,
1589					(const char *)"SYMINENT");
1590				(void) printf(Fmtptr,
1591					EC_XWORD(p_dyn.d_un.d_val));
1592				break;
1593
1594			/*
1595			 * SUNW: DT_ADDRRNGLO - DT_ADDRRNGHI range.
1596			 */
1597			case (DT_CONFIG):
1598				(void) printf(Fmttag, (const char *)"CONFIG");
1599				if (v_flag)
1600					dt_name = (char *)elf_strptr(elf_file,
1601					    link, p_dyn.d_un.d_ptr);
1602				if (dt_name == NULL)
1603					dt_name = (char *)UNKNOWN;
1604				if (v_flag && strlen(dt_name))
1605					(void) printf("%s", dt_name);
1606				else
1607					(void) printf(Fmtptr,
1608						EC_ADDR(p_dyn.d_un.d_ptr));
1609				break;
1610			case (DT_DEPAUDIT):
1611				(void) printf(Fmttag,
1612					(const char *)"DEPAUDIT");
1613				if (v_flag)
1614					dt_name = (char *)elf_strptr(elf_file,
1615					    link, p_dyn.d_un.d_ptr);
1616				if (dt_name == NULL)
1617					dt_name = (char *)UNKNOWN;
1618				if (v_flag && strlen(dt_name))
1619					(void) printf("%s", dt_name);
1620				else
1621					(void) printf(Fmtptr,
1622						EC_ADDR(p_dyn.d_un.d_ptr));
1623				break;
1624			case (DT_AUDIT):
1625				(void) printf(Fmttag,
1626					(const char *)"AUDIT");
1627				if (v_flag)
1628					dt_name = (char *)elf_strptr(elf_file,
1629					    link, p_dyn.d_un.d_ptr);
1630				if (dt_name == NULL)
1631					dt_name = (char *)UNKNOWN;
1632				if (v_flag && strlen(dt_name))
1633					(void) printf("%s", dt_name);
1634				else
1635					(void) printf(Fmtptr,
1636						EC_ADDR(p_dyn.d_un.d_ptr));
1637				break;
1638			case (DT_PLTPAD):
1639				(void) printf(Fmttag,
1640					(const char *)"PLTPAD");
1641				(void) printf(Fmtptr,
1642					EC_ADDR(p_dyn.d_un.d_ptr));
1643				break;
1644			case (DT_MOVETAB):
1645				(void) printf(Fmttag,
1646					(const char *)"MOVETAB");
1647				(void) printf(Fmtptr,
1648					EC_ADDR(p_dyn.d_un.d_ptr));
1649				break;
1650			case (DT_SYMINFO):
1651				(void) printf(Fmttag,
1652					(const char *)"SYMINFO");
1653				(void) printf(Fmtptr,
1654					EC_ADDR(p_dyn.d_un.d_ptr));
1655				break;
1656
1657			/*
1658			 * SUNW: generic range.
1659			 */
1660			case (DT_RELACOUNT):
1661				(void) printf(Fmttag,
1662					(const char *)"RELACOUNT");
1663				(void) printf(Fmtptr,
1664					EC_ADDR(p_dyn.d_un.d_ptr));
1665				break;
1666			case (DT_RELCOUNT):
1667				(void) printf(Fmttag,
1668					(const char *)"RELCOUNT");
1669				(void) printf(Fmtptr,
1670					EC_ADDR(p_dyn.d_un.d_ptr));
1671				break;
1672			case (DT_FLAGS_1):
1673				(void) printf(Fmttag,
1674				    (const char *)"FLAGS_1");
1675				value[0] = '\0';
1676				if (v_flag) {
1677					if (p_dyn.d_un.d_val & DF_1_NOW)
1678					    (void) strcat(value,
1679						(const char *)"NOW ");
1680					if (p_dyn.d_un.d_val & DF_1_GLOBAL)
1681					    (void) strcat(value,
1682						(const char *)"GLOBAL ");
1683					if (p_dyn.d_un.d_val & DF_1_GROUP)
1684					    (void) strcat(value,
1685						(const char *)"GROUP ");
1686					if (p_dyn.d_un.d_val & DF_1_NODELETE)
1687					    (void) strcat(value,
1688						(const char *)"NODELETE ");
1689					if (p_dyn.d_un.d_val & DF_1_LOADFLTR)
1690					    (void) strcat(value,
1691						(const char *)"LOADFLTR ");
1692					if (p_dyn.d_un.d_val & DF_1_INITFIRST)
1693					    (void) strcat(value,
1694						(const char *)"INITFIRST ");
1695					if (p_dyn.d_un.d_val & DF_1_NOOPEN)
1696					    (void) strcat(value,
1697						(const char *)"NOOPEN ");
1698					if (p_dyn.d_un.d_val & DF_1_ORIGIN)
1699					    (void) strcat(value,
1700						(const char *)"ORIGIN ");
1701					if (p_dyn.d_un.d_val & DF_1_DIRECT)
1702					    (void) strcat(value,
1703						(const char *)"DIRECT ");
1704					if (p_dyn.d_un.d_val & DF_1_TRANS)
1705					    (void) strcat(value,
1706						(const char *)"TRANS ");
1707					if (p_dyn.d_un.d_val & DF_1_INTERPOSE)
1708					    (void) strcat(value,
1709						(const char *)"INTERPOSE ");
1710					if (p_dyn.d_un.d_val & DF_1_NODEFLIB)
1711					    (void) strcat(value,
1712						(const char *)"NODEFLIB ");
1713					if (p_dyn.d_un.d_val & DF_1_NODUMP)
1714					    (void) strcat(value,
1715						(const char *)"NODUMP ");
1716					if (p_dyn.d_un.d_val & DF_1_CONFALT)
1717					    (void) strcat(value,
1718						(const char *)"CONFALT ");
1719					if (p_dyn.d_un.d_val & DF_1_ENDFILTEE)
1720					    (void) strcat(value,
1721						(const char *)"ENDFILTEE ");
1722					if (p_dyn.d_un.d_val & DF_1_DISPRELDNE)
1723					    (void) strcat(value,
1724						(const char *)"DISPRELDONE ");
1725					if (p_dyn.d_un.d_val & DF_1_DISPRELPND)
1726					    (void) strcat(value,
1727						(const char *)"DISPRELPND ");
1728					if (p_dyn.d_un.d_val & DF_1_IGNMULDEF)
1729					    (void) strcat(value,
1730						(const char *)"IGNMULDEF ");
1731					if (p_dyn.d_un.d_val & DF_1_NOKSYMS)
1732					    (void) strcat(value,
1733						(const char *)"NOKSYMS ");
1734				}
1735				if (v_flag && strlen(value))
1736					(void) printf("%s", value);
1737				else
1738					(void) printf(Fmtptr,
1739						EC_ADDR(p_dyn.d_un.d_ptr));
1740				break;
1741			case (DT_VERSYM):
1742				(void) printf(Fmttag, (const char *)"VERSYM");
1743				(void) printf(Fmtptr,
1744					EC_ADDR(p_dyn.d_un.d_ptr));
1745				break;
1746			case (DT_VERDEF):
1747				(void) printf(Fmttag, (const char *)"VERDEF");
1748				(void) printf(Fmtptr,
1749					EC_ADDR(p_dyn.d_un.d_ptr));
1750				break;
1751			case (DT_VERDEFNUM):
1752				(void) printf(Fmttag,
1753				    (const char *)"VERDEFNUM");
1754				(void) printf(Fmtptr,
1755					EC_XWORD(p_dyn.d_un.d_val));
1756				break;
1757			case (DT_VERNEED):
1758				(void) printf(Fmttag, (const char *)"VERNEED");
1759				(void) printf(Fmtptr,
1760					EC_ADDR(p_dyn.d_un.d_ptr));
1761				break;
1762			case (DT_VERNEEDNUM):
1763				(void) printf(Fmttag,
1764				    (const char *)"VERNEEDNUM");
1765				(void) printf(Fmtptr,
1766					EC_XWORD(p_dyn.d_un.d_val));
1767				break;
1768			case (DT_AUXILIARY):
1769				(void) printf(Fmttag,
1770					(const char *)"AUXILIARY");
1771				if (v_flag)
1772					dt_name = (char *)elf_strptr(elf_file,
1773					    link, p_dyn.d_un.d_ptr);
1774				if (dt_name == NULL)
1775					dt_name = (char *)UNKNOWN;
1776				if (v_flag && strlen(dt_name))
1777					(void) printf("%s", dt_name);
1778				else
1779					(void) printf(Fmtptr,
1780						EC_ADDR(p_dyn.d_un.d_ptr));
1781				break;
1782			case (DT_USED):
1783				(void) printf(Fmttag, (const char *)"USED");
1784				if (v_flag)
1785					dt_name = (char *)elf_strptr(elf_file,
1786					    link, p_dyn.d_un.d_ptr);
1787				if (dt_name == NULL)
1788					dt_name = (char *)UNKNOWN;
1789				if (v_flag && strlen(dt_name))
1790					(void) printf("%s", dt_name);
1791				else
1792					(void) printf(Fmtptr,
1793						EC_ADDR(p_dyn.d_un.d_ptr));
1794				break;
1795			case (DT_FILTER):
1796				(void) printf(Fmttag, (const char *)"FILTER");
1797				if (v_flag)
1798					dt_name = (char *)elf_strptr(elf_file,
1799					    link, p_dyn.d_un.d_ptr);
1800				if (dt_name == NULL)
1801					dt_name = (char *)UNKNOWN;
1802				if (v_flag && strlen(dt_name))
1803					(void) printf("%s", dt_name);
1804				else
1805					(void) printf(Fmtptr,
1806						EC_ADDR(p_dyn.d_un.d_ptr));
1807				break;
1808
1809			/*
1810			 * SUNW: machine specific range.
1811			 */
1812			case (DT_SPARC_REGISTER):
1813				(void) printf(Fmttag,
1814					(const char *)"REGISTER");
1815				(void) printf(Fmtptr,
1816					EC_XWORD(p_dyn.d_un.d_val));
1817				break;
1818			case (DT_DEPRECATED_SPARC_REGISTER):
1819				(void) printf(Fmttag,
1820					(const char *)"REGISTER");
1821				(void) printf("%#llx  (deprecated value)",
1822					EC_XWORD(p_dyn.d_un.d_val));
1823				break;
1824			default:
1825				(void) printf("%lld", EC_XWORD(p_dyn.d_tag));
1826				break;
1827			}
1828			(void) printf("\n");
1829			(void) gelf_getdyn(dyn_data, ii++, &p_dyn);
1830		}
1831	}
1832
1833	/*
1834	 * Check for existence of static shared library information.
1835	 */
1836	(void) gelf_getehdr(elf_file, &p_ehdr);
1837	while (header_num < p_ehdr.e_phnum) {
1838		(void) gelf_getphdr(elf_file, header_num, &p_phdr);
1839		if (p_phdr.p_type == PT_SHLIB) {
1840			while (--lib_scns > 0) {
1841				if (strcmp(l_scns->scn_name, ".lib") == 0) {
1842					print_static(l_scns, filename);
1843				}
1844				l_scns++;
1845			}
1846		}
1847		header_num++;
1848	}
1849}
1850
1851/*
1852 * Print the ELF header.  Input is an ELF file descriptor
1853 * and the filename.  If f_flag is set, the ELF header is
1854 * printed to stdout, otherwise the function returns after
1855 * setting the pointer to the ELF header.  Any values which
1856 * are not known are printed in decimal.  Fields must be updated
1857 * as new values are added.
1858 */
1859static GElf_Ehdr *
1860dump_elf_header(Elf *elf_file, char *filename, GElf_Ehdr * elf_head_p)
1861{
1862	int class, data;
1863	int field;
1864
1865	if (gelf_getehdr(elf_file, elf_head_p) == NULL) {
1866		(void) fprintf(stderr, "%s: %s: %s\n", prog_name, filename,
1867		    elf_errmsg(-1));
1868		return (NULL);
1869	}
1870
1871	class = (int)elf_head_p->e_ident[4];
1872
1873	if (class == ELFCLASS64)
1874		field = 21;
1875	else
1876		field = 13;
1877
1878	if (!f_flag)
1879		return (elf_head_p);
1880
1881	if (!p_flag) {
1882		(void) printf("\n                    **** ELF HEADER ****\n");
1883		(void) printf("%-*s%-11s%-*sMachine     Version\n",
1884		    field, "Class", "Data", field, "Type");
1885		(void) printf("%-*s%-11s%-*sFlags       Ehsize\n",
1886		    field, "Entry", "Phoff", field, "Shoff");
1887		(void) printf("%-*s%-11s%-*sShnum       Shstrndx\n\n",
1888		    field, "Phentsize", "Phnum", field, "Shentsz");
1889	}
1890
1891	if (!v_flag) {
1892		(void) printf("%-*d%-11d%-*d%-12d%d\n",
1893			field, elf_head_p->e_ident[4],
1894			elf_head_p->e_ident[5],
1895			field, (int)elf_head_p->e_type,
1896			(int)elf_head_p->e_machine,
1897			elf_head_p->e_version);
1898	} else {
1899		data = elf_head_p->e_ident[5];
1900
1901		switch (class) {
1902		case ELFCLASSNONE:
1903			(void) printf("%-*s", field, "None");
1904			break;
1905		case ELFCLASS32:
1906			(void) printf("%-*s", field, "32-bit");
1907			break;
1908		case ELFCLASS64:
1909			(void) printf("%-*s", field, "64-bit");
1910			break;
1911		default:
1912			(void) printf("%-*d", field, class);
1913			break;
1914		}
1915		switch (data) {
1916		case ELFDATANONE:
1917			(void) printf("%-11s", "None   ");
1918			break;
1919		case ELFDATA2LSB:
1920			(void) printf("%-11s", "2LSB   ");
1921			break;
1922		case ELFDATA2MSB:
1923			(void) printf("%-11s", "2MSB   ");
1924			break;
1925		default:
1926			(void) printf("%-11d", data);
1927			break;
1928		}
1929
1930		switch (elf_head_p->e_type) {
1931		case ET_NONE:
1932			(void) printf("%-*s", field, "None");
1933			break;
1934		case ET_REL:
1935			(void) printf("%-*s", field, "Reloc");
1936			break;
1937		case ET_EXEC:
1938			(void) printf("%-*s", field, "Exec");
1939			break;
1940		case ET_DYN:
1941			(void) printf("%-*s", field, "Dyn");
1942			break;
1943		case ET_CORE:
1944			(void) printf("%-*s", field, "Core");
1945			break;
1946		default:
1947			(void) printf("%-*d", field,
1948				EC_WORD(elf_head_p->e_type));
1949			break;
1950		}
1951		switch (elf_head_p->e_machine) {
1952		case EM_NONE:
1953			(void) printf("%-12s", "No mach");
1954			break;
1955		case EM_M32:
1956			(void) printf("%-12s", "WE32100");
1957			break;
1958		case EM_SPARC:
1959			(void) printf("%-12s", "SPARC");
1960			break;
1961		case EM_SPARCV9:
1962			(void) printf("%-12s", "SPARCV9");
1963			break;
1964		case EM_386:
1965			(void) printf("%-12s", "80386");
1966			break;
1967		case EM_68K:
1968			(void) printf("%-12s", "68000");
1969			break;
1970		case EM_88K:
1971			(void) printf("%-12s", "88000");
1972			break;
1973		case EM_486:
1974			(void) printf("%-12s", "80486");
1975			break;
1976		case EM_860:
1977			(void) printf("%-12s", "i860");
1978			break;
1979		case EM_MIPS:
1980			(void) printf("%-12s", "RS3000_BE");
1981			break;
1982		case EM_MIPS_RS3_LE:
1983			(void) printf("%-12s", "RS3000_LE");
1984			break;
1985		case EM_RS6000:
1986			(void) printf("%-12s", "RS6000");
1987			break;
1988		case EM_PA_RISC:
1989			(void) printf("%-12s", "PA_RISC");
1990			break;
1991		case EM_nCUBE:
1992			(void) printf("%-12s", "nCUBE");
1993			break;
1994		case EM_VPP500:
1995			(void) printf("%-12s", "VPP500");
1996			break;
1997		case EM_SPARC32PLUS:
1998			(void) printf("%-12s", "SPARC32PLUS");
1999			break;
2000		case EM_PPC:
2001			(void) printf("%-12s", "PowerPC");
2002			break;
2003		case EM_IA_64:
2004			(void) printf("%-12s", "IA64");
2005			break;
2006		default:
2007			(void) printf("%-12d", EC_WORD(elf_head_p->e_machine));
2008		}
2009		switch (elf_head_p->e_version) {
2010		case EV_NONE:
2011			(void) printf("Invalid\n");
2012			break;
2013		case EV_CURRENT:
2014			(void) printf("Current\n");
2015			break;
2016		default:
2017			(void) printf("%d\n", elf_head_p->e_version);
2018		}
2019	}
2020	(void) printf("%-#*llx%-#11llx%-#*llx%-#12x%#x\n",
2021		field, EC_ADDR(elf_head_p->e_entry),
2022		EC_OFF(elf_head_p->e_phoff),
2023		field, EC_OFF(elf_head_p->e_shoff),
2024		EC_WORD(elf_head_p->e_flags),
2025		EC_WORD(elf_head_p->e_ehsize));
2026	if (!v_flag || (elf_head_p->e_shstrndx != SHN_XINDEX)) {
2027		(void) printf("%-#*x%-11u%-#*x%-12u%u\n",
2028			field, EC_WORD(elf_head_p->e_phentsize),
2029			EC_WORD(elf_head_p->e_phnum),
2030			field, EC_WORD(elf_head_p->e_shentsize),
2031			EC_WORD(elf_head_p->e_shnum),
2032			EC_WORD(elf_head_p->e_shstrndx));
2033	} else {
2034		(void) printf("%-#*x%-11u%-#*x%-12uXINDEX\n",
2035			field, EC_WORD(elf_head_p->e_phentsize),
2036			EC_WORD(elf_head_p->e_phnum),
2037			field, EC_WORD(elf_head_p->e_shentsize),
2038			EC_WORD(elf_head_p->e_shnum));
2039	}
2040	if ((elf_head_p->e_shnum == 0) && (elf_head_p->e_shoff > 0)) {
2041		Elf_Scn		*scn;
2042		GElf_Shdr	shdr0;
2043		int		field;
2044
2045		if (gelf_getclass(elf_file) == ELFCLASS64)
2046			field = 21;
2047		else
2048			field = 13;
2049		if (!p_flag) {
2050			(void) printf("\n	   **** SECTION HEADER[0] "
2051			    "{Elf Extensions} ****\n");
2052			(void) printf(
2053			    "[No]\tType\tFlags\t%-*s %-*s%-*s%sName\n",
2054			    field, "Addr", field, "Offset", field,
2055			    "Size(shnum)",
2056			    /* compatibility:  tab for elf32 */
2057			    (field == 13) ? "\t" : "  ");
2058			(void) printf("\tLn(strndx) Info\t%-*s Entsize\n",
2059			    field, "Adralgn");
2060		}
2061		if ((scn = elf_getscn(elf_file, 0)) == NULL) {
2062			(void) fprintf(stderr,
2063				"%s: %s: elf_getscn failed: %s\n",
2064				prog_name, filename, elf_errmsg(-1));
2065			return (NULL);
2066		}
2067		if (gelf_getshdr(scn, &shdr0) == 0) {
2068			(void) fprintf(stderr,
2069				"%s: %s: gelf_getshdr: %s\n",
2070				prog_name, filename, elf_errmsg(-1));
2071			return (NULL);
2072		}
2073		(void) printf("[0]\t%u\t%llu\t", EC_WORD(shdr0.sh_type),
2074			EC_XWORD(shdr0.sh_flags));
2075
2076		/*
2077		 * LINTED - field and EC_XWORD cause -#*llu complaints that
2078		 * even this comment can't shutup.
2079		 */
2080		(void) printf("%-#*llx %-#*llx%-#*llu%s%-#*u\n",
2081			field, EC_ADDR(shdr0.sh_addr),
2082			field, EC_OFF(shdr0.sh_offset),
2083			field, EC_XWORD(shdr0.sh_size),
2084			/* compatibility:  tab for elf32 */
2085			((field == 13) ? "\t" : "  "),
2086			field, EC_WORD(shdr0.sh_name));
2087
2088		(void) printf("\t%u\t%u\t%-#*llx %-#*llx\n",
2089			EC_WORD(shdr0.sh_link),
2090			EC_WORD(shdr0.sh_info),
2091			field, EC_XWORD(shdr0.sh_addralign),
2092			field, EC_XWORD(shdr0.sh_entsize));
2093	}
2094	(void) printf("\n");
2095
2096	return (elf_head_p);
2097}
2098
2099/*
2100 * Print section contents.  Input is an ELF file descriptor,
2101 * the ELF header, the SCNTAB structure,
2102 * the number of symbols, and the filename.
2103 * The number of sections,
2104 * and the offset into the SCNTAB structure will be
2105 * set in dump_section if d_flag or n_flag are set.
2106 * If v_flag is set, sections which can be interpreted will
2107 * be interpreted, otherwise raw data will be output in hexidecimal.
2108 */
2109static void
2110print_section(Elf *elf_file,
2111	GElf_Ehdr *p_ehdr, SCNTAB *p, int num_scns, char *filename)
2112{
2113	unsigned char    *p_sec;
2114	int	i;
2115	size_t	size;
2116
2117	for (i = 0; i < num_scns; i++, p++) {
2118		GElf_Shdr shdr;
2119
2120		size = 0;
2121		if (s_flag && !v_flag)
2122			p_sec = (unsigned char *)get_rawscn(p->p_sd, &size);
2123		else
2124			p_sec = (unsigned char *)get_scndata(p->p_sd, &size);
2125
2126		if ((gelf_getshdr(p->p_sd, &shdr) != NULL) &&
2127		    (shdr.sh_type == SHT_NOBITS)) {
2128			continue;
2129		}
2130		if (s_flag && !v_flag) {
2131			(void) printf("\n%s:\n", p->scn_name);
2132			print_rawdata(p_sec, size);
2133			continue;
2134		}
2135		if (shdr.sh_type == SHT_SYMTAB) {
2136			dump_symbol_table(elf_file, p, filename);
2137			continue;
2138		}
2139		if (shdr.sh_type == SHT_DYNSYM) {
2140			dump_symbol_table(elf_file, p, filename);
2141			continue;
2142		}
2143		if (shdr.sh_type == SHT_STRTAB) {
2144			dump_string_table(p, 1);
2145			continue;
2146		}
2147		if (shdr.sh_type == SHT_RELA) {
2148			dump_reloc_table(elf_file, p_ehdr, p, 1, filename);
2149			continue;
2150		}
2151		if (shdr.sh_type == SHT_REL) {
2152			dump_reloc_table(elf_file, p_ehdr, p, 1, filename);
2153			continue;
2154		}
2155		if (shdr.sh_type == SHT_DYNAMIC) {
2156			dump_dynamic(elf_file, p, 1, filename);
2157			continue;
2158		}
2159
2160		(void) printf("\n%s:\n", p->scn_name);
2161		print_rawdata(p_sec, size);
2162	}
2163	(void) printf("\n");
2164}
2165
2166/*
2167 * Print section contents. This function does not print the contents
2168 * of the sections but sets up the parameters and then calls
2169 * print_section to print the contents.  Calling another function to print
2170 * the contents allows both -d and -n to work correctly
2171 * simultaneously. Input is an ELF file descriptor, the ELF header,
2172 * the SCNTAB structure, the number of sections, and the filename.
2173 * Set the range of sections if d_flag, and set section name if
2174 * n_flag.
2175 */
2176static void
2177dump_section(Elf *elf_file,
2178	GElf_Ehdr *p_ehdr, SCNTAB *s, int num_scns, char *filename)
2179{
2180	SCNTAB *n_range, *d_range; /* for use with -n and -d modifiers */
2181	int i;
2182	int found_it = 0;  /* for use with -n section_name */
2183
2184	if (n_flag) {
2185		n_range = s;
2186
2187		for (i = 0; i < num_scns; i++, n_range++) {
2188			if ((strcmp(name, n_range->scn_name)) != 0)
2189				continue;
2190			else {
2191				found_it = 1;
2192				print_section(elf_file, p_ehdr,
2193					n_range, 1, filename);
2194			}
2195		}
2196
2197		if (!found_it) {
2198			(void) fprintf(stderr, "%s: %s: %s not found\n",
2199				prog_name, filename, name);
2200		}
2201	} /* end n_flag */
2202
2203	if (d_flag) {
2204		d_range = s;
2205		d_num = check_range(d_low, d_hi, num_scns, filename);
2206		if (d_num < 0)
2207			return;
2208		d_range += d_low - 1;
2209
2210		print_section(elf_file, p_ehdr, d_range, d_num, filename);
2211	}	/* end d_flag */
2212
2213	if (!n_flag && !d_flag)
2214		print_section(elf_file, p_ehdr, s, num_scns, filename);
2215}
2216
2217/*
2218 * Print the section header table. This function does not print the contents
2219 * of the section headers but sets up the parameters and then calls
2220 * print_shdr to print the contents.  Calling another function to print
2221 * the contents allows both -d and -n to work correctly
2222 * simultaneously.  Input is the SCNTAB structure,
2223 * the number of sections from the ELF header, and the filename.
2224 * Set the range of section headers to print if d_flag, and set
2225 * name of section header to print if n_flag.
2226 */
2227static void
2228dump_shdr(Elf *elf_file, SCNTAB *s, int num_scns, char *filename)
2229{
2230
2231	SCNTAB *n_range, *d_range;	/* for use with -n and -d modifiers */
2232	int field;
2233	int i;
2234	int found_it = 0;  /* for use with -n section_name */
2235
2236	if (gelf_getclass(elf_file) == ELFCLASS64)
2237		field = 21;
2238	else
2239		field = 13;
2240
2241	if (!p_flag) {
2242		(void) printf("\n	   **** SECTION HEADER TABLE ****\n");
2243		(void) printf("[No]\tType\tFlags\t%-*s %-*s %-*s%sName\n",
2244		    field, "Addr", field, "Offset", field, "Size",
2245		    /* compatibility:  tab for elf32 */
2246		    (field == 13) ? "\t" : "  ");
2247		(void) printf("\tLink\tInfo\t%-*s Entsize\n\n",
2248		    field, "Adralgn");
2249	}
2250
2251	if (n_flag) {
2252		n_range = s;
2253
2254		for (i = 1; i <= num_scns; i++, n_range++) {
2255			if ((strcmp(name, n_range->scn_name)) != 0)
2256				continue;
2257			else {
2258				found_it = 1;
2259				print_shdr(elf_file, n_range, 1, i);
2260			}
2261		}
2262
2263		if (!found_it) {
2264			(void) fprintf(stderr, "%s: %s: %s not found\n",
2265				prog_name, filename, name);
2266		}
2267	} /* end n_flag */
2268
2269	if (d_flag) {
2270		d_range = s;
2271		d_num = check_range(d_low, d_hi, num_scns, filename);
2272		if (d_num < 0)
2273			return;
2274		d_range += d_low - 1;
2275
2276		print_shdr(elf_file, d_range, d_num, d_low);
2277	}	/* end d_flag */
2278
2279	if (!n_flag && !d_flag)
2280		print_shdr(elf_file, s, num_scns, 1);
2281}
2282
2283/*
2284 * Process all of the command line options (except
2285 * for -a, -g, -f, and -o).  All of the options processed
2286 * by this function require the presence of the section
2287 * header table and will not be processed if it is not present.
2288 * Set up a buffer containing section name, section header,
2289 * and section descriptor for each section in the file.  This
2290 * structure is used to avoid duplicate calls to libelf functions.
2291 * Structure members for the symbol table, the debugging information,
2292 * and the line number information are global.  All of the
2293 * rest are local.
2294 */
2295static void
2296dump_section_table(Elf *elf_file, GElf_Ehdr *elf_head_p, char *filename)
2297{
2298
2299	static SCNTAB	*buffer, *p_scns;
2300	Elf_Scn		*scn = 0;
2301	char		*s_name = NULL;
2302	int		found = 0;
2303	unsigned int	num_scns;
2304	size_t		shstrndx;
2305	size_t		shnum;
2306
2307
2308	if (elf_getshnum(elf_file, &shnum) == 0) {
2309		(void) fprintf(stderr,
2310			"%s: %s: elf_getshnum failed: %s\n",
2311			prog_name, filename, elf_errmsg(-1));
2312		return;
2313	}
2314	if (elf_getshstrndx(elf_file, &shstrndx) == 0) {
2315		(void) fprintf(stderr,
2316			"%s: %s: elf_getshstrndx failed: %s\n",
2317			prog_name, filename, elf_errmsg(-1));
2318		return;
2319	}
2320
2321	if ((buffer = calloc(shnum, sizeof (SCNTAB))) == NULL) {
2322		(void) fprintf(stderr, "%s: %s: cannot calloc space\n",
2323			prog_name, filename);
2324		return;
2325	}
2326	/* LINTED */
2327	num_scns = (int)shnum - 1;
2328
2329	p_symtab = (SCNTAB *)0;
2330	p_dynsym = (SCNTAB *)0;
2331	p_scns = buffer;
2332	p_head_scns = buffer;
2333
2334	while ((scn = elf_nextscn(elf_file, scn)) != 0) {
2335		if ((gelf_getshdr(scn, &buffer->p_shdr)) == 0) {
2336			(void) fprintf(stderr,
2337			"%s: %s: %s\n", prog_name, filename, elf_errmsg(-1));
2338			return;
2339		}
2340		s_name = (char *)elf_strptr(elf_file,
2341			shstrndx, buffer->p_shdr.sh_name);
2342		buffer->scn_name = s_name ? s_name : (char *)UNKNOWN;
2343		buffer->p_sd   =  scn;
2344
2345		if (buffer->p_shdr.sh_type == SHT_SYMTAB) {
2346			found += 1;
2347			p_symtab = buffer;
2348		}
2349		if (buffer->p_shdr.sh_type == SHT_DYNSYM)
2350			p_dynsym = buffer;
2351		buffer++;
2352	}
2353
2354	/*
2355	 * These functions depend upon the presence of the section header table
2356	 * and will not be invoked in its absence
2357	 */
2358	if (h_flag) {
2359		dump_shdr(elf_file, p_scns, num_scns, filename);
2360	}
2361	if (p_symtab && (t_flag || T_flag)) {
2362		dump_symbol_table(elf_file, p_symtab, filename);
2363	}
2364	if (c_flag) {
2365		dump_string_table(p_scns, num_scns);
2366	}
2367	if (r_flag) {
2368		dump_reloc_table(elf_file, elf_head_p,
2369			p_scns, num_scns, filename);
2370	}
2371	if (L_flag) {
2372		dump_dynamic(elf_file, p_scns, num_scns, filename);
2373	}
2374	if (s_flag) {
2375		dump_section(elf_file, elf_head_p, p_scns,
2376			num_scns, filename);
2377	}
2378}
2379
2380/*
2381 * Load the archive string table(s) (for extended-length strings)
2382 * into an in-core table/list
2383 */
2384static struct stab_list_s *
2385load_arstring_table(struct stab_list_s *STabList,
2386	int fd, Elf *elf_file, Elf_Arhdr *p_ar, char *filename)
2387{
2388	off_t here;
2389	struct stab_list_s *STL_entry, *STL_next;
2390
2391	if (p_ar) {
2392		STL_entry = malloc(sizeof (struct stab_list_s));
2393		STL_entry->next    = 0;
2394		STL_entry->strings = 0;
2395		STL_entry->size    = 0;
2396
2397		if (!STabList)
2398			STabList = STL_entry;
2399		else {
2400			STL_next = STabList;
2401			while (STL_next->next != (void *)0)
2402				STL_next = STL_next->next;
2403			STL_next->next = STL_entry;
2404		}
2405
2406		STL_entry->size    = p_ar->ar_size;
2407		STL_entry->strings = malloc(p_ar->ar_size);
2408		here = elf_getbase(elf_file);
2409		if ((lseek(fd, here, 0)) != here) {
2410			(void) fprintf(stderr,
2411			"%s: %s: could not lseek\n", prog_name, filename);
2412		}
2413
2414		if ((read(fd, STL_entry->strings, p_ar->ar_size)) == -1) {
2415			(void) fprintf(stderr,
2416			"%s: %s: could not read\n", prog_name, filename);
2417		}
2418	}
2419	return (STabList);
2420}
2421
2422/*
2423 * Print the archive header for each member of an archive.
2424 * Also call ar_sym_read to print the symbols in the
2425 * archive symbol table if g_flag.  Input is a file descriptor,
2426 * an ELF file descriptor, and the filename.  Putting the call
2427 * to dump the archive symbol table in this function is more
2428 * efficient since it is necessary to examine the archive member
2429 * name in the archive header to determine which member is the
2430 * symbol table.
2431 */
2432static void
2433dump_ar_hdr(int fd, Elf *elf_file, char *filename)
2434{
2435	extern int v_flag, g_flag, a_flag, p_flag;
2436	Elf_Arhdr  *p_ar;
2437	Elf *arf;
2438	Elf_Cmd cmd;
2439	int title = 0;
2440	int err = 0;
2441
2442	char buf[DATESIZE];
2443
2444	cmd = ELF_C_READ;
2445	while ((arf = elf_begin(fd, cmd, elf_file)) != 0) {
2446		p_ar = elf_getarhdr(arf);
2447		if (p_ar == NULL) {
2448			(void) fprintf(stderr,
2449			"%s: %s: %s\n", prog_name, filename, elf_errmsg(-1));
2450			continue;
2451		}
2452		if (strcmp(p_ar->ar_name, "/") == 0) {
2453			if (g_flag)
2454				ar_sym_read(elf_file, filename);
2455		} else if (strcmp(p_ar->ar_name, "//") == 0) {
2456			StringTableList = load_arstring_table(
2457				StringTableList, fd, arf, p_ar,
2458				filename);
2459			cmd = elf_next(arf);
2460			(void) elf_end(arf);
2461			continue;
2462		} else {
2463			if (a_flag) {
2464				(void) printf("%s[%s]:\n", filename,
2465					p_ar->ar_name);
2466				if (!p_flag && title == 0) {
2467					if (!v_flag)
2468						(void) printf(
2469"\n\n\t\t\t***ARCHIVE HEADER***"
2470"\n	Date          Uid     Gid    Mode      Size	 Member Name\n\n");
2471					else
2472						(void) printf(
2473"\n\n\t\t\t***ARCHIVE HEADER***"
2474"\n	Date                   Uid    Gid   Mode     Size     Member Name\n\n");
2475					title = 1;
2476				}
2477				if (!v_flag) {
2478					(void) printf(
2479"\t0x%.8lx  %6d  %6d  0%.6ho  0x%.8lx  %-s\n\n",
2480						p_ar->ar_date,
2481						(int)p_ar->ar_uid,
2482						(int)p_ar->ar_gid,
2483						(int)p_ar->ar_mode,
2484						p_ar->ar_size,
2485						p_ar->ar_name);
2486				} else {
2487					if ((strftime(buf, DATESIZE,
2488					    "%b %d %H:%M:%S %Y",
2489					    localtime(
2490					    &(p_ar->ar_date)))) == 0) {
2491						(void) fprintf(stderr,
2492"%s: %s: don't have enough space to store the date\n", prog_name, filename);
2493						exit(1);
2494					}
2495					(void) printf(
2496					"\t%s %6d %6d 0%.6ho 0x%.8lx %-s\n\n",
2497						buf,
2498						(int)p_ar->ar_uid,
2499						(int)p_ar->ar_gid,
2500						(int)p_ar->ar_mode,
2501						p_ar->ar_size,
2502						p_ar->ar_name);
2503				}
2504			}
2505		}
2506		cmd = elf_next(arf);
2507		(void) elf_end(arf);
2508	} /* end while */
2509
2510	err = elf_errno();
2511	if (err != 0) {
2512		(void) fprintf(stderr,
2513		"%s: %s: %s\n", prog_name, filename, elf_errmsg(err));
2514	}
2515}
2516
2517/*
2518 * Process member files of an archive.  This function provides
2519 * a loop through an archive equivalent the processing of
2520 * each_file for individual object files.
2521 */
2522static void
2523dump_ar_files(int fd, Elf *elf_file, char *filename)
2524{
2525	Elf_Arhdr  *p_ar;
2526	Elf *arf;
2527	Elf_Cmd cmd;
2528	Elf_Kind file_type;
2529	GElf_Ehdr elf_head;
2530	char *fullname;
2531
2532	cmd = ELF_C_READ;
2533	while ((arf = elf_begin(fd, cmd, elf_file)) != 0) {
2534		size_t	len;
2535
2536		p_ar = elf_getarhdr(arf);
2537		if (p_ar == NULL) {
2538			(void) fprintf(stderr,
2539				"%s: %s: %s\n",
2540				prog_name, filename, elf_errmsg(-1));
2541			return;
2542		}
2543		if ((strcmp(p_ar->ar_name, "/") == 0) ||
2544			(strcmp(p_ar->ar_name, "//") == 0)) {
2545			cmd = elf_next(arf);
2546			(void) elf_end(arf);
2547			continue;
2548		}
2549
2550		len = strlen(filename) + strlen(p_ar->ar_name) + 3;
2551		if ((fullname = malloc(len)) == NULL)
2552			return;
2553		(void) snprintf(fullname, len, "%s[%s]", filename,
2554		    p_ar->ar_name);
2555		(void) printf("\n%s:\n", fullname);
2556		file_type = elf_kind(arf);
2557		if (file_type == ELF_K_ELF) {
2558			if (dump_elf_header(arf, fullname, &elf_head) == NULL)
2559				return;
2560			if (o_flag)
2561				dump_exec_header(arf,
2562					(unsigned)elf_head.e_phnum, fullname);
2563			if (x_flag)
2564				dump_section_table(arf, &elf_head, fullname);
2565		} else {
2566			(void) fprintf(stderr,
2567				"%s: %s: invalid file type\n",
2568				prog_name, fullname);
2569			cmd = elf_next(arf);
2570			(void) elf_end(arf);
2571			continue;
2572		}
2573
2574		cmd = elf_next(arf);
2575		(void) elf_end(arf);
2576	} /* end while */
2577}
2578
2579/*
2580 * Takes a filename as input.  Test first for a valid version
2581 * of libelf.a and exit on error.  Process each valid file
2582 * or archive given as input on the command line.  Check
2583 * for file type.  If it is an archive, process the archive-
2584 * specific options first, then files within the archive.
2585 * If it is an ELF object file, process it; otherwise
2586 * warn that it is an invalid file type.
2587 * All options except the archive-specific and program
2588 * execution header are processed in the function, dump_section_table.
2589 */
2590static void
2591each_file(char *filename)
2592{
2593	Elf *elf_file;
2594	GElf_Ehdr elf_head;
2595	int fd;
2596	Elf_Kind   file_type;
2597
2598	struct stat buf;
2599
2600	Elf_Cmd cmd;
2601	errno = 0;
2602
2603	if (stat(filename, &buf) == -1) {
2604		int	err = errno;
2605		(void) fprintf(stderr, "%s: %s: %s", prog_name, filename,
2606		    strerror(err));
2607		return;
2608	}
2609
2610	if ((fd = open((filename), O_RDONLY)) == -1) {
2611		(void) fprintf(stderr, "%s: %s: cannot read\n", prog_name,
2612		    filename);
2613		return;
2614	}
2615	cmd = ELF_C_READ;
2616	if ((elf_file = elf_begin(fd, cmd, (Elf *)0)) == NULL) {
2617		(void) fprintf(stderr, "%s: %s: %s\n", prog_name, filename,
2618		    elf_errmsg(-1));
2619		return;
2620	}
2621
2622	file_type = elf_kind(elf_file);
2623	if (file_type == ELF_K_AR) {
2624		if (a_flag || g_flag) {
2625			dump_ar_hdr(fd, elf_file, filename);
2626			elf_file = elf_begin(fd, cmd, (Elf *)0);
2627		}
2628		if (z_flag)
2629			dump_ar_files(fd, elf_file, filename);
2630	} else {
2631		if (file_type == ELF_K_ELF) {
2632			(void) printf("\n%s:\n", filename);
2633			if (dump_elf_header(elf_file, filename, &elf_head)) {
2634				if (o_flag)
2635					dump_exec_header(elf_file,
2636					    (unsigned)elf_head.e_phnum,
2637					    filename);
2638				if (x_flag)
2639					dump_section_table(elf_file,
2640					    &elf_head, filename);
2641			}
2642		} else {
2643			(void) fprintf(stderr, "%s: %s: invalid file type\n",
2644			    prog_name, filename);
2645		}
2646	}
2647	(void) elf_end(elf_file);
2648	(void) close(fd);
2649}
2650
2651/*
2652 * Sets up flags for command line options given and then
2653 * calls each_file() to process each file.
2654 */
2655int
2656main(int argc, char *argv[], char *envp[])
2657{
2658	char *optstr = OPTSTR; /* option string used by getopt() */
2659	int optchar;
2660
2661	/*
2662	 * Check for a binary that better fits this architecture.
2663	 */
2664	conv_check_native(argv, envp);
2665
2666	prog_name = argv[0];
2667
2668	(void) setlocale(LC_ALL, "");
2669	while ((optchar = getopt(argc, argv, optstr)) != -1) {
2670		switch (optchar) {
2671		case 'a':
2672			a_flag = 1;
2673			x_flag = 1;
2674			break;
2675		case 'g':
2676			g_flag = 1;
2677			x_flag = 1;
2678			break;
2679		case 'v':
2680			v_flag = 1;
2681			break;
2682		case 'p':
2683			p_flag = 1;
2684			break;
2685		case 'f':
2686			f_flag = 1;
2687			z_flag = 1;
2688			break;
2689		case 'o':
2690			o_flag = 1;
2691			z_flag = 1;
2692			break;
2693		case 'h':
2694			h_flag = 1;
2695			x_flag = 1;
2696			z_flag = 1;
2697			break;
2698		case 's':
2699			s_flag = 1;
2700			x_flag = 1;
2701			z_flag = 1;
2702			break;
2703		case 'd':
2704			d_flag = 1;
2705			x_flag = 1;
2706			z_flag = 1;
2707			set_range(optarg, &d_low, &d_hi);
2708			break;
2709		case 'n':
2710			n_flag++;
2711			x_flag = 1;
2712			z_flag = 1;
2713			name = optarg;
2714			break;
2715		case 'r':
2716			r_flag = 1;
2717			x_flag = 1;
2718			z_flag = 1;
2719			break;
2720		case 't':
2721			t_flag = 1;
2722			x_flag = 1;
2723			z_flag = 1;
2724			break;
2725		case 'C':
2726			C_flag = 1;
2727			t_flag = 1;
2728			x_flag = 1;
2729			z_flag = 1;
2730			break;
2731		case 'T':
2732			T_flag = 1;
2733			x_flag = 1;
2734			z_flag = 1;
2735			set_range(optarg, &T_low, &T_hi);
2736			break;
2737		case 'c':
2738			c_flag = 1;
2739			x_flag = 1;
2740			z_flag = 1;
2741			break;
2742		case 'L':
2743			L_flag = 1;
2744			x_flag = 1;
2745			z_flag = 1;
2746			break;
2747		case 'V':
2748			V_flag = 1;
2749			(void) fprintf(stderr, "dump: %s %s\n",
2750			    (const char *)SGU_PKG,
2751			    (const char *)SGU_REL);
2752			break;
2753		case '?':
2754			errflag += 1;
2755			break;
2756		default:
2757			break;
2758		}
2759	}
2760
2761	if (errflag || (optind >= argc) || (!z_flag && !x_flag)) {
2762		if (!(V_flag && (argc == 2))) {
2763			usage();
2764			exit(269);
2765		}
2766	}
2767
2768	if (elf_version(EV_CURRENT) == EV_NONE) {
2769		(void) fprintf(stderr, "%s: libelf is out of date\n",
2770		    prog_name);
2771		exit(101);
2772	}
2773
2774	while (optind < argc) {
2775		each_file(argv[optind]);
2776		optind++;
2777	}
2778	return (0);
2779}
2780