xref: /onnv-gate/usr/src/cmd/sgs/pvs/common/pvs.c (revision 2647:e440e3da2a6f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51618Srie  * Common Development and Distribution License (the "License").
61618Srie  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211618Srie 
220Sstevel@tonic-gate /*
231618Srie  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Analyze the versioning information within a file.
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  *   -C		demangle C++ symbol names.
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  *   -d		dump version definitions.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  *   -l		print reduced (local) symbols.
370Sstevel@tonic-gate  *
380Sstevel@tonic-gate  *   -n		normalize any version definitions.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  *   -o		dump output in one-line fashion	(more suitable for grep'ing
410Sstevel@tonic-gate  *		and diff'ing).
420Sstevel@tonic-gate  *
430Sstevel@tonic-gate  *   -r		dump the version requirements on library dependencies
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  *   -s		display the symbols associated with each version definition.
460Sstevel@tonic-gate  *
470Sstevel@tonic-gate  *   -v		verbose output.  With the -r and -d options any WEAK attribute
480Sstevel@tonic-gate  *		is displayed.  With the -d option, any version inheritance,
490Sstevel@tonic-gate  *		and the base version are displayed.  With the -s option the
500Sstevel@tonic-gate  *		version symbol is displayed.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  *   -N name	only print the specifed `name'.
530Sstevel@tonic-gate  */
540Sstevel@tonic-gate #include	<fcntl.h>
550Sstevel@tonic-gate #include	<stdio.h>
560Sstevel@tonic-gate #include	<libelf.h>
570Sstevel@tonic-gate #include	<link.h>
580Sstevel@tonic-gate #include	<stdlib.h>
590Sstevel@tonic-gate #include	<string.h>
600Sstevel@tonic-gate #include	<unistd.h>
610Sstevel@tonic-gate #include	<locale.h>
620Sstevel@tonic-gate #include	<errno.h>
631618Srie #include	<sgs.h>
641618Srie #include	<conv.h>
651618Srie #include	<gelf.h>
661618Srie #include	<debug.h>
670Sstevel@tonic-gate #include	"msg.h"
680Sstevel@tonic-gate 
690Sstevel@tonic-gate #define		FLG_VER_AVAIL	0x10
700Sstevel@tonic-gate 
710Sstevel@tonic-gate typedef struct cache {
720Sstevel@tonic-gate 	Elf_Scn		*c_scn;
730Sstevel@tonic-gate 	Elf_Data	*c_data;
740Sstevel@tonic-gate 	char		*c_name;
750Sstevel@tonic-gate } Cache;
760Sstevel@tonic-gate 
770Sstevel@tonic-gate typedef struct gver_desc {
780Sstevel@tonic-gate 	const char	*vd_name;
790Sstevel@tonic-gate 	unsigned long	vd_hash;
800Sstevel@tonic-gate 	GElf_Half	vd_ndx;
810Sstevel@tonic-gate 	GElf_Half	vd_flags;
820Sstevel@tonic-gate 	List		vd_deps;
830Sstevel@tonic-gate } GVer_desc;
840Sstevel@tonic-gate 
850Sstevel@tonic-gate static const char	*cname;
860Sstevel@tonic-gate static int		Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate static const char
890Sstevel@tonic-gate 	* Format_ofil = "%s -",
900Sstevel@tonic-gate 	* Format_tnco =	"\t%s:\n",
910Sstevel@tonic-gate 	* Format_tnse =	"\t%s;\n",
920Sstevel@tonic-gate 	* Format_bgnl = "\t%s (%s",
930Sstevel@tonic-gate 	* Format_next = ", %s",
940Sstevel@tonic-gate 	* Format_weak = " [WEAK]",
950Sstevel@tonic-gate 	* Format_endl = ");\n";
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #define	DEF_DEFINED	1
980Sstevel@tonic-gate #define	USR_DEFINED	2
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate /*
1010Sstevel@tonic-gate  * Determine whether a symbol name should be demangled.
1020Sstevel@tonic-gate  */
1030Sstevel@tonic-gate static const char *
1040Sstevel@tonic-gate demangle(const char *name)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate 	if (Cflag)
1071618Srie 		return (Elf_demangle_name(name));
1080Sstevel@tonic-gate 	else
1090Sstevel@tonic-gate 		return (name);
1100Sstevel@tonic-gate }
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * Print any reduced symbols.  The convention is that reduced symbols exist as
1140Sstevel@tonic-gate  * LOCL entries in the .symtab, between the FILE symbol for the output file and
1150Sstevel@tonic-gate  * the first FILE symbol for any input file used to build the output file.
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate static void
1180Sstevel@tonic-gate sym_local(Cache *cache, Cache *csym, const char *file)
1190Sstevel@tonic-gate {
1200Sstevel@tonic-gate 	int		symn, _symn, found = 0;
1210Sstevel@tonic-gate 	GElf_Shdr	shdr;
1220Sstevel@tonic-gate 	GElf_Sym	sym;
1230Sstevel@tonic-gate 	char		*strs, *local = "_LOCAL_";
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate 	(void) gelf_getshdr(csym->c_scn, &shdr);
1260Sstevel@tonic-gate 	strs = (char *)cache[shdr.sh_link].c_data->d_buf;
1270Sstevel@tonic-gate 	/* LINTED */
1280Sstevel@tonic-gate 	symn = shdr.sh_info;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/*
1310Sstevel@tonic-gate 	 * Verify symtab[1] is the output file symbol.
1320Sstevel@tonic-gate 	 */
1330Sstevel@tonic-gate 	(void) gelf_getsym(csym->c_data, 1, &sym);
1340Sstevel@tonic-gate 	if (GELF_ST_TYPE(sym.st_info) != STT_FILE) {
1350Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname,
1360Sstevel@tonic-gate 		    file);
1370Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE),
1380Sstevel@tonic-gate 		    csym->c_name);
1390Sstevel@tonic-gate 		return;
1400Sstevel@tonic-gate 	}
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate 	/*
1430Sstevel@tonic-gate 	 * Scan the remaining symbols until the next file symbol is found.
1440Sstevel@tonic-gate 	 */
1450Sstevel@tonic-gate 	for (_symn = 2; _symn < symn; _symn++) {
1460Sstevel@tonic-gate 		const char	*name;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 		(void) gelf_getsym(csym->c_data, _symn, &sym);
1490Sstevel@tonic-gate 		if (GELF_ST_TYPE(sym.st_info) == STT_SECTION)
1500Sstevel@tonic-gate 			continue;
1510Sstevel@tonic-gate 		if (GELF_ST_TYPE(sym.st_info) == STT_FILE)
1520Sstevel@tonic-gate 			break;
1530Sstevel@tonic-gate 
1540Sstevel@tonic-gate 		/*
1550Sstevel@tonic-gate 		 * Its possible that section symbols are followed immediately
1560Sstevel@tonic-gate 		 * by globals.  This is the case if an object (filter) is
1570Sstevel@tonic-gate 		 * generated exclusively from mapfile symbol definitions.
1580Sstevel@tonic-gate 		 */
1590Sstevel@tonic-gate 		if (GELF_ST_BIND(sym.st_info) != STB_LOCAL)
1600Sstevel@tonic-gate 			break;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 		name = demangle(strs + sym.st_name);
1630Sstevel@tonic-gate 
1640Sstevel@tonic-gate 		if (oflag) {
1650Sstevel@tonic-gate 			(void) printf(Format_ofil, file);
1660Sstevel@tonic-gate 			(void) printf("\t%s: %s\n", local, name);
1670Sstevel@tonic-gate 		} else {
1680Sstevel@tonic-gate 			if (found == 0) {
1690Sstevel@tonic-gate 				found = 1;
1700Sstevel@tonic-gate 				(void) printf(Format_tnco, local);
1710Sstevel@tonic-gate 			}
1720Sstevel@tonic-gate 			(void) printf("\t\t%s;\n", name);
1730Sstevel@tonic-gate 		}
1740Sstevel@tonic-gate 	}
1750Sstevel@tonic-gate }
1760Sstevel@tonic-gate 
1770Sstevel@tonic-gate /*
1780Sstevel@tonic-gate  * Print the files version needed sections.
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate static int
1810Sstevel@tonic-gate gvers_need(Cache *cache, Cache *need, const char *file, const char *name)
1820Sstevel@tonic-gate {
1830Sstevel@tonic-gate 	unsigned int	num, _num;
1840Sstevel@tonic-gate 	char		*strs;
1850Sstevel@tonic-gate 	GElf_Verneed	*vnd = need->c_data->d_buf;
1860Sstevel@tonic-gate 	GElf_Shdr	shdr;
1870Sstevel@tonic-gate 	int		error = 0;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate 	(void) gelf_getshdr(need->c_scn, &shdr);
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/*
1920Sstevel@tonic-gate 	 * Verify the version revision.  We only check the first version
1930Sstevel@tonic-gate 	 * structure as it is assumed all other version structures in this
1940Sstevel@tonic-gate 	 * data section will be of the same revision.
1950Sstevel@tonic-gate 	 */
1960Sstevel@tonic-gate 	if (vnd->vn_version > VER_DEF_CURRENT)
1970Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file,
1980Sstevel@tonic-gate 		    vnd->vn_version, VER_DEF_CURRENT);
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate 	/*
2010Sstevel@tonic-gate 	 * Get the data buffer for the associated string table.
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	strs = (char *)cache[shdr.sh_link].c_data->d_buf;
2040Sstevel@tonic-gate 	num = shdr.sh_info;
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
2070Sstevel@tonic-gate 	    vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) {
2080Sstevel@tonic-gate 		GElf_Vernaux	*vnap = (GElf_Vernaux *)
2090Sstevel@tonic-gate 					((uintptr_t)vnd + vnd->vn_aux);
2100Sstevel@tonic-gate 		GElf_Half	cnt = vnd->vn_cnt;
2110Sstevel@tonic-gate 		const char	*_name, * dep;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 		/*
2140Sstevel@tonic-gate 		 * Obtain the version name and determine if we need to process
2150Sstevel@tonic-gate 		 * it further.
2160Sstevel@tonic-gate 		 */
2170Sstevel@tonic-gate 		_name = (char *)(strs + vnd->vn_file);
2180Sstevel@tonic-gate 		if (name && (strcmp(name, _name) == 0))
2190Sstevel@tonic-gate 			continue;
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 		error = 1;
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 		/*
2240Sstevel@tonic-gate 		 * If one-line ouput is called for display the filename being
2250Sstevel@tonic-gate 		 * processed.
2260Sstevel@tonic-gate 		 */
2270Sstevel@tonic-gate 		if (oflag)
2280Sstevel@tonic-gate 			(void) printf(Format_ofil, file);
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 		/*
2310Sstevel@tonic-gate 		 * Determine the version name required from this file.
2320Sstevel@tonic-gate 		 */
2330Sstevel@tonic-gate 		if (cnt--)
2340Sstevel@tonic-gate 			dep = (char *)(strs + vnap->vna_name);
2350Sstevel@tonic-gate 		else
2360Sstevel@tonic-gate 			dep = MSG_ORIG(MSG_STR_EMPTY);
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate 		(void) printf(Format_bgnl, _name, dep);
2390Sstevel@tonic-gate 		if (vflag && (vnap->vna_flags == VER_FLG_WEAK))
2400Sstevel@tonic-gate 			(void) printf(Format_weak);
2410Sstevel@tonic-gate 
2420Sstevel@tonic-gate 		/*
2430Sstevel@tonic-gate 		 * Extract any other version dependencies for this file
2440Sstevel@tonic-gate 		 */
2450Sstevel@tonic-gate 		/* CSTYLED */
2460Sstevel@tonic-gate 		for (vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next);
2470Sstevel@tonic-gate 		    cnt; cnt--,
2480Sstevel@tonic-gate 		    vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) {
2490Sstevel@tonic-gate 			dep = (char *)(strs + vnap->vna_name);
2500Sstevel@tonic-gate 			(void) printf(Format_next, dep);
2510Sstevel@tonic-gate 			if (vflag && (vnap->vna_flags == VER_FLG_WEAK))
2520Sstevel@tonic-gate 				(void) printf(Format_weak);
2530Sstevel@tonic-gate 		}
2540Sstevel@tonic-gate 		(void) printf(Format_endl);
2550Sstevel@tonic-gate 	}
2560Sstevel@tonic-gate 	return (error);
2570Sstevel@tonic-gate }
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate /*
2600Sstevel@tonic-gate  * Append an item to the specified list, and return a pointer to the list
2610Sstevel@tonic-gate  * node created.
2620Sstevel@tonic-gate  */
2630Sstevel@tonic-gate static Listnode *
2640Sstevel@tonic-gate list_append(List *lst, const void *item, const char *file)
2650Sstevel@tonic-gate {
2660Sstevel@tonic-gate 	Listnode	*_lnp;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	if ((_lnp = malloc(sizeof (Listnode))) == 0) {
2690Sstevel@tonic-gate 		int err = errno;
2700Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file,
2710Sstevel@tonic-gate 		    strerror(err));
2720Sstevel@tonic-gate 		exit(1);
2730Sstevel@tonic-gate 	}
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	_lnp->data = (void *)item;
2760Sstevel@tonic-gate 	_lnp->next = NULL;
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate 	if (lst->head == NULL)
2790Sstevel@tonic-gate 		lst->tail = lst->head = _lnp;
2800Sstevel@tonic-gate 	else {
2810Sstevel@tonic-gate 		lst->tail->next = _lnp;
2820Sstevel@tonic-gate 		lst->tail = lst->tail->next;
2830Sstevel@tonic-gate 	}
2840Sstevel@tonic-gate 	return (_lnp);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate static GVer_desc *
2880Sstevel@tonic-gate gvers_find(const char *name, unsigned long hash, List *lst)
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	Listnode	*lnp;
2910Sstevel@tonic-gate 	GVer_desc	*vdp;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	for (LIST_TRAVERSE(lst, lnp, vdp)) {
2940Sstevel@tonic-gate 		if (vdp->vd_hash != hash)
2950Sstevel@tonic-gate 			continue;
2960Sstevel@tonic-gate 		if (strcmp(vdp->vd_name, name) == 0)
2970Sstevel@tonic-gate 			return (vdp);
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 	return (0);
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate static GVer_desc *
3030Sstevel@tonic-gate gvers_desc(const char *name, unsigned long hash, List *lst, const char *file)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	GVer_desc	*vdp;
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	if ((vdp = gvers_find(name, hash, lst)) == 0) {
3080Sstevel@tonic-gate 		if ((vdp = calloc(sizeof (GVer_desc), 1)) == 0) {
3090Sstevel@tonic-gate 			int err = errno;
3100Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
3110Sstevel@tonic-gate 			    file, strerror(err));
3120Sstevel@tonic-gate 			exit(1);
3130Sstevel@tonic-gate 		}
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 		vdp->vd_name = name;
3160Sstevel@tonic-gate 		vdp->vd_hash = hash;
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 		if (list_append(lst, vdp, file) == 0)
3190Sstevel@tonic-gate 			return (0);
3200Sstevel@tonic-gate 	}
3210Sstevel@tonic-gate 	return (vdp);
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate static GVer_desc *
3250Sstevel@tonic-gate gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, List *lst,
3260Sstevel@tonic-gate     const char *file)
3270Sstevel@tonic-gate {
3280Sstevel@tonic-gate 	GVer_desc	*_vdp;
3290Sstevel@tonic-gate 
3300Sstevel@tonic-gate 	if ((_vdp = gvers_desc(name, hash, lst, file)) == 0)
3310Sstevel@tonic-gate 		return (0);
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 	if (list_append(&vdp->vd_deps, _vdp, file) == 0)
3340Sstevel@tonic-gate 		return (0);
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 	return (vdp);
3370Sstevel@tonic-gate }
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate static void
3400Sstevel@tonic-gate gvers_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs,
3410Sstevel@tonic-gate     GVer_desc *vdp, const char *file)
3420Sstevel@tonic-gate {
3430Sstevel@tonic-gate 	GElf_Sym	sym;
3440Sstevel@tonic-gate 	int		_symn;
3450Sstevel@tonic-gate 
3460Sstevel@tonic-gate 	for (_symn = 0; _symn < symn; _symn++) {
3470Sstevel@tonic-gate 		size_t		size =	0;
3480Sstevel@tonic-gate 		const char	*name;
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 		if (vsp[_symn] != vdp->vd_ndx)
3510Sstevel@tonic-gate 			continue;
3520Sstevel@tonic-gate 
3530Sstevel@tonic-gate 		/*
3540Sstevel@tonic-gate 		 * For data symbols determine the size.
3550Sstevel@tonic-gate 		 */
3560Sstevel@tonic-gate 		(void) gelf_getsym(sym_data, _symn, &sym);
3570Sstevel@tonic-gate 		if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) ||
3580Sstevel@tonic-gate 		    (GELF_ST_TYPE(sym.st_info) == STT_COMMON) ||
3590Sstevel@tonic-gate 		    (GELF_ST_TYPE(sym.st_info) == STT_TLS))
3600Sstevel@tonic-gate 			size = (size_t)sym.st_size;
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 		name = demangle(strs + sym.st_name);
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate 		/*
3650Sstevel@tonic-gate 		 * Only output the version symbol when the verbose flag is used.
3660Sstevel@tonic-gate 		 */
3670Sstevel@tonic-gate 		if (!vflag && (sym.st_shndx == SHN_ABS)) {
3680Sstevel@tonic-gate 			if (strcmp(name, vdp->vd_name) == 0)
3690Sstevel@tonic-gate 				continue;
3700Sstevel@tonic-gate 		}
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 		if (oflag) {
3730Sstevel@tonic-gate 			(void) printf(Format_ofil, file);
3740Sstevel@tonic-gate 			(void) printf("\t%s: ", vdp->vd_name);
3750Sstevel@tonic-gate 			if (size)
3760Sstevel@tonic-gate 				(void) printf("%s (%ld);\n", name,
3770Sstevel@tonic-gate 				    (ulong_t)size);
3780Sstevel@tonic-gate 			else
3790Sstevel@tonic-gate 				(void) printf("%s;\n", name);
3800Sstevel@tonic-gate 		} else {
3810Sstevel@tonic-gate 			if (size)
3820Sstevel@tonic-gate 				(void) printf("\t\t%s (%ld);\n", name,
3830Sstevel@tonic-gate 				    (ulong_t)size);
3840Sstevel@tonic-gate 			else
3850Sstevel@tonic-gate 				(void) printf("\t\t%s;\n", name);
3860Sstevel@tonic-gate 		}
3870Sstevel@tonic-gate 	}
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate static void
3910Sstevel@tonic-gate gvers_derefer(GVer_desc * vdp, int weak)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	Listnode *	_lnp;
3940Sstevel@tonic-gate 	GVer_desc *	_vdp;
3950Sstevel@tonic-gate 
3960Sstevel@tonic-gate 	/*
3970Sstevel@tonic-gate 	 * If the head of the list was a weak then we only clear out
3980Sstevel@tonic-gate 	 * weak dependencies, but if the head of the list was 'strong'
3990Sstevel@tonic-gate 	 * we clear the REFER bit on all dependencies.
4000Sstevel@tonic-gate 	 */
4010Sstevel@tonic-gate 	if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak))
4020Sstevel@tonic-gate 		vdp->vd_flags &= ~FLG_VER_AVAIL;
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp))
4050Sstevel@tonic-gate 		gvers_derefer(_vdp, weak);
4060Sstevel@tonic-gate }
4070Sstevel@tonic-gate 
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate static void
4100Sstevel@tonic-gate recurse_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs,
4110Sstevel@tonic-gate     GVer_desc *vdp, const char *file)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	Listnode	*_lnp;
4140Sstevel@tonic-gate 	GVer_desc	*_vdp;
4150Sstevel@tonic-gate 
4160Sstevel@tonic-gate 	for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) {
4170Sstevel@tonic-gate 		if (!oflag)
4180Sstevel@tonic-gate 			(void) printf(Format_tnco, _vdp->vd_name);
4190Sstevel@tonic-gate 		gvers_syms(vsp, sym_data, symn, strs, _vdp, file);
4200Sstevel@tonic-gate 		if (_vdp->vd_deps.head)
4210Sstevel@tonic-gate 			recurse_syms(vsp, sym_data, symn, strs, _vdp, file);
4220Sstevel@tonic-gate 	}
4230Sstevel@tonic-gate }
4240Sstevel@tonic-gate 
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate /*
4270Sstevel@tonic-gate  * Print the files version definition sections.
4280Sstevel@tonic-gate  */
4290Sstevel@tonic-gate static int
4300Sstevel@tonic-gate gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file,
4310Sstevel@tonic-gate     const char *name)
4320Sstevel@tonic-gate {
4330Sstevel@tonic-gate 	unsigned int	num, _num;
4340Sstevel@tonic-gate 	char		*strs;
4350Sstevel@tonic-gate 	GElf_Versym	*vsp;
4360Sstevel@tonic-gate 	GElf_Verdef	*vdf = def->c_data->d_buf;
4370Sstevel@tonic-gate 	GElf_Shdr	shdr;
4380Sstevel@tonic-gate 	Elf_Data	*sym_data;
4390Sstevel@tonic-gate 	int		symn;
4400Sstevel@tonic-gate 	GVer_desc	*vdp, *bvdp = 0;
4410Sstevel@tonic-gate 	Listnode	*lnp;
4420Sstevel@tonic-gate 	List		verdefs = {0, 0};
4430Sstevel@tonic-gate 	int		error = 0;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	/*
4460Sstevel@tonic-gate 	 * Verify the version revision.  We only check the first version
4470Sstevel@tonic-gate 	 * structure as it is assumed all other version structures in this
4480Sstevel@tonic-gate 	 * data section will be of the same revision.
4490Sstevel@tonic-gate 	 */
4500Sstevel@tonic-gate 	if (vdf->vd_version > VER_DEF_CURRENT) {
4510Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file,
4520Sstevel@tonic-gate 		    vdf->vd_version, VER_DEF_CURRENT);
4530Sstevel@tonic-gate 	}
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate 	/*
4560Sstevel@tonic-gate 	 * Get the data buffer for the associated string table.
4570Sstevel@tonic-gate 	 */
4580Sstevel@tonic-gate 	(void) gelf_getshdr(def->c_scn, &shdr);
4590Sstevel@tonic-gate 	strs = (char *)cache[shdr.sh_link].c_data->d_buf;
4600Sstevel@tonic-gate 	num = shdr.sh_info;
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate 	/*
4630Sstevel@tonic-gate 	 * Process the version definitions placing each on a version dependency
4640Sstevel@tonic-gate 	 * list.
4650Sstevel@tonic-gate 	 */
4660Sstevel@tonic-gate 	for (_num = 1; _num <= num; _num++,
4670Sstevel@tonic-gate 	    vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) {
4680Sstevel@tonic-gate 		GElf_Half	cnt = vdf->vd_cnt;
4690Sstevel@tonic-gate 		GElf_Half	ndx = vdf->vd_ndx;
4700Sstevel@tonic-gate 		GElf_Verdaux	*vdap = (GElf_Verdaux *)((uintptr_t)vdf +
4710Sstevel@tonic-gate 				    vdf->vd_aux);
4720Sstevel@tonic-gate 		const char	*_name;
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 		/*
4750Sstevel@tonic-gate 		 * Determine the version name and any dependencies.
4760Sstevel@tonic-gate 		 */
4770Sstevel@tonic-gate 		_name = (char *)(strs + vdap->vda_name);
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 		if ((vdp = gvers_desc(_name, elf_hash(_name), &verdefs,
4800Sstevel@tonic-gate 		    file)) == 0)
4810Sstevel@tonic-gate 			return (0);
4820Sstevel@tonic-gate 		vdp->vd_ndx = ndx;
4830Sstevel@tonic-gate 		vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 		vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next);
4860Sstevel@tonic-gate 		for (cnt--; cnt; cnt--,
4870Sstevel@tonic-gate 		    vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) {
4880Sstevel@tonic-gate 			_name = (char *)(strs + vdap->vda_name);
4890Sstevel@tonic-gate 			if (gvers_depend(_name, elf_hash(_name), vdp,
4900Sstevel@tonic-gate 			    &verdefs, file) == 0)
4910Sstevel@tonic-gate 				return (0);
4920Sstevel@tonic-gate 		}
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 		/*
4950Sstevel@tonic-gate 		 * Remember the base version for possible later use.
4960Sstevel@tonic-gate 		 */
4970Sstevel@tonic-gate 		if (ndx == VER_NDX_GLOBAL)
4980Sstevel@tonic-gate 			bvdp = vdp;
4990Sstevel@tonic-gate 	}
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate 	/*
5020Sstevel@tonic-gate 	 * Normalize the dependency list if required.
5030Sstevel@tonic-gate 	 */
5040Sstevel@tonic-gate 	if (nflag) {
5050Sstevel@tonic-gate 		for (LIST_TRAVERSE(&verdefs, lnp, vdp)) {
5060Sstevel@tonic-gate 			Listnode *	_lnp;
5070Sstevel@tonic-gate 			GVer_desc *	_vdp;
5080Sstevel@tonic-gate 			int		type = vdp->vd_flags & VER_FLG_WEAK;
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 			for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp))
5110Sstevel@tonic-gate 				gvers_derefer(_vdp, type);
5120Sstevel@tonic-gate 		}
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 		/*
5150Sstevel@tonic-gate 		 * Always dereference the base version.
5160Sstevel@tonic-gate 		 */
5170Sstevel@tonic-gate 		if (bvdp)
5180Sstevel@tonic-gate 			bvdp->vd_flags &= ~FLG_VER_AVAIL;
5190Sstevel@tonic-gate 	}
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 	/*
5230Sstevel@tonic-gate 	 * Traverse the dependency list and print out the appropriate
5240Sstevel@tonic-gate 	 * information.
5250Sstevel@tonic-gate 	 */
5260Sstevel@tonic-gate 	for (LIST_TRAVERSE(&verdefs, lnp, vdp)) {
5270Sstevel@tonic-gate 		Listnode *	_lnp;
5280Sstevel@tonic-gate 		GVer_desc *	_vdp;
5290Sstevel@tonic-gate 		int		count;
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate 		if (name && (strcmp(name, vdp->vd_name) != 0))
5320Sstevel@tonic-gate 			continue;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 		if (!name && !(vdp->vd_flags & FLG_VER_AVAIL))
5350Sstevel@tonic-gate 			continue;
5360Sstevel@tonic-gate 
5370Sstevel@tonic-gate 		error = 1;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 		if (vflag) {
5400Sstevel@tonic-gate 			/*
5410Sstevel@tonic-gate 			 * If the verbose flag is set determine if this version
5420Sstevel@tonic-gate 			 * has a `weak' attribute, and print any version
5430Sstevel@tonic-gate 			 * dependencies this version inherits.
5440Sstevel@tonic-gate 			 */
5450Sstevel@tonic-gate 			if (oflag)
5460Sstevel@tonic-gate 				(void) printf(Format_ofil, file);
5470Sstevel@tonic-gate 			(void) printf("\t%s", vdp->vd_name);
5480Sstevel@tonic-gate 			if (vdp->vd_flags & VER_FLG_WEAK)
5490Sstevel@tonic-gate 				(void) printf(Format_weak);
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate 			count = 1;
5520Sstevel@tonic-gate 			for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) {
5530Sstevel@tonic-gate 				const char	*_name = _vdp->vd_name;
5540Sstevel@tonic-gate 
5550Sstevel@tonic-gate 				if (count++ == 1) {
5560Sstevel@tonic-gate 					if (oflag)
5570Sstevel@tonic-gate 						(void) printf(": {%s", _name);
5580Sstevel@tonic-gate 					else if (vdp->vd_flags & VER_FLG_WEAK)
5590Sstevel@tonic-gate 						(void) printf(":\t{%s", _name);
5600Sstevel@tonic-gate 					else
5610Sstevel@tonic-gate 						(void) printf(":       \t{%s",
5620Sstevel@tonic-gate 						    _name);
5630Sstevel@tonic-gate 				} else
5640Sstevel@tonic-gate 					(void) printf(Format_next, _name);
5650Sstevel@tonic-gate 			}
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 			if (count != 1)
5680Sstevel@tonic-gate 				(void) printf("}");
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 			if (csym && !oflag)
5710Sstevel@tonic-gate 				(void) printf(":\n");
5720Sstevel@tonic-gate 			else
5730Sstevel@tonic-gate 				(void) printf(";\n");
5740Sstevel@tonic-gate 		} else {
5750Sstevel@tonic-gate 			if (csym && !oflag)
5760Sstevel@tonic-gate 				(void) printf(Format_tnco, vdp->vd_name);
5770Sstevel@tonic-gate 			else if (!csym) {
5780Sstevel@tonic-gate 				if (oflag)
5790Sstevel@tonic-gate 					(void) printf(Format_ofil, file);
5800Sstevel@tonic-gate 				(void) printf(Format_tnse, vdp->vd_name);
5810Sstevel@tonic-gate 			}
5820Sstevel@tonic-gate 		}
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 		/*
5850Sstevel@tonic-gate 		 * If we need to print symbols get the associated symbol table.
5860Sstevel@tonic-gate 		 */
5870Sstevel@tonic-gate 		if (csym) {
5880Sstevel@tonic-gate 			(void) gelf_getshdr(csym->c_scn, &shdr);
5890Sstevel@tonic-gate 			vsp = (GElf_Versym *)csym->c_data->d_buf;
5900Sstevel@tonic-gate 			sym_data = cache[shdr.sh_link].c_data;
5910Sstevel@tonic-gate 			(void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr);
5920Sstevel@tonic-gate 			/* LINTED */
5930Sstevel@tonic-gate 			symn = (int)(shdr.sh_size / shdr.sh_entsize);
5940Sstevel@tonic-gate 		} else
5950Sstevel@tonic-gate 			continue;
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 		/*
5980Sstevel@tonic-gate 		 * If a specific version name has been specified then display
5990Sstevel@tonic-gate 		 * any of its own symbols plus any inherited from other
6000Sstevel@tonic-gate 		 * versions.  Otherwise simply print out the symbols for this
6010Sstevel@tonic-gate 		 * version.
6020Sstevel@tonic-gate 		 */
6030Sstevel@tonic-gate 		gvers_syms(vsp, sym_data, symn, strs, vdp, file);
6040Sstevel@tonic-gate 		if (name) {
6050Sstevel@tonic-gate 			recurse_syms(vsp, sym_data, symn, strs, vdp, file);
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 			/*
6080Sstevel@tonic-gate 			 * If the verbose flag is set add the base version as a
6090Sstevel@tonic-gate 			 * dependency (unless it's the list we were asked to
6100Sstevel@tonic-gate 			 * print in the first place).
6110Sstevel@tonic-gate 			 */
6120Sstevel@tonic-gate 			if (vflag && bvdp && strcmp(name, bvdp->vd_name)) {
6130Sstevel@tonic-gate 				if (!oflag)
6140Sstevel@tonic-gate 				    (void) printf(Format_tnco, bvdp->vd_name);
6150Sstevel@tonic-gate 				gvers_syms(vsp, sym_data, symn, strs, bvdp,
6160Sstevel@tonic-gate 				    file);
6170Sstevel@tonic-gate 			}
6180Sstevel@tonic-gate 		}
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 	return (error);
6210Sstevel@tonic-gate }
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate int
6240Sstevel@tonic-gate main(int argc, char **argv, char **envp)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	GElf_Shdr	shdr;
6270Sstevel@tonic-gate 	Elf		*elf;
6280Sstevel@tonic-gate 	Elf_Scn		*scn;
6290Sstevel@tonic-gate 	Elf_Data	*data;
6300Sstevel@tonic-gate 	GElf_Ehdr 	ehdr;
6310Sstevel@tonic-gate 	int		nfile, var;
6320Sstevel@tonic-gate 	const char	*name;
6330Sstevel@tonic-gate 	char		*names;
6340Sstevel@tonic-gate 	Cache		*cache, *_cache;
6350Sstevel@tonic-gate 	Cache		*_cache_def, *_cache_need, *_cache_sym, *_cache_loc;
6360Sstevel@tonic-gate 	int		error = 0;
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	/*
6390Sstevel@tonic-gate 	 * Check for a binary that better fits this architecture.
6400Sstevel@tonic-gate 	 */
641*2647Srie 	(void) conv_check_native(argv, envp);
6420Sstevel@tonic-gate 
6430Sstevel@tonic-gate 	/*
6440Sstevel@tonic-gate 	 * Establish locale.
6450Sstevel@tonic-gate 	 */
6460Sstevel@tonic-gate 	(void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY));
6470Sstevel@tonic-gate 	(void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS));
6480Sstevel@tonic-gate 
6490Sstevel@tonic-gate 	cname = argv[0];
6500Sstevel@tonic-gate 	name = NULL;
6510Sstevel@tonic-gate 	Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 	opterr = 0;
6540Sstevel@tonic-gate 	while ((var = getopt(argc, argv, "CdlnorsvN:")) != EOF) {
6550Sstevel@tonic-gate 		switch (var) {
6560Sstevel@tonic-gate 		case 'C':
6570Sstevel@tonic-gate 			Cflag = USR_DEFINED;
6580Sstevel@tonic-gate 			break;
6590Sstevel@tonic-gate 		case 'd':
6600Sstevel@tonic-gate 			dflag = USR_DEFINED;
6610Sstevel@tonic-gate 			break;
6620Sstevel@tonic-gate 		case 'l':
6630Sstevel@tonic-gate 			lflag = USR_DEFINED;
6640Sstevel@tonic-gate 			break;
6650Sstevel@tonic-gate 		case 'n':
6660Sstevel@tonic-gate 			nflag = USR_DEFINED;
6670Sstevel@tonic-gate 			break;
6680Sstevel@tonic-gate 		case 'o':
6690Sstevel@tonic-gate 			oflag = USR_DEFINED;
6700Sstevel@tonic-gate 			break;
6710Sstevel@tonic-gate 		case 'r':
6720Sstevel@tonic-gate 			rflag = USR_DEFINED;
6730Sstevel@tonic-gate 			break;
6740Sstevel@tonic-gate 		case 's':
6750Sstevel@tonic-gate 			sflag = USR_DEFINED;
6760Sstevel@tonic-gate 			break;
6770Sstevel@tonic-gate 		case 'v':
6780Sstevel@tonic-gate 			vflag = USR_DEFINED;
6790Sstevel@tonic-gate 			break;
6800Sstevel@tonic-gate 		case 'N':
6810Sstevel@tonic-gate 			name = optarg;
6820Sstevel@tonic-gate 			break;
6830Sstevel@tonic-gate 		case '?':
6840Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF),
6850Sstevel@tonic-gate 			    cname);
6860Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL));
6870Sstevel@tonic-gate 			exit(1);
6880Sstevel@tonic-gate 		default:
6890Sstevel@tonic-gate 			break;
6900Sstevel@tonic-gate 		}
6910Sstevel@tonic-gate 	}
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	/*
6940Sstevel@tonic-gate 	 * No files specified on the command line?
6950Sstevel@tonic-gate 	 */
6960Sstevel@tonic-gate 	if ((nfile = argc - optind) == 0) {
6970Sstevel@tonic-gate 		(void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname);
6980Sstevel@tonic-gate 		exit(1);
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	/*
7020Sstevel@tonic-gate 	 * By default print both version definitions and needed dependencies.
7030Sstevel@tonic-gate 	 */
7040Sstevel@tonic-gate 	if ((dflag == 0) && (rflag == 0))
7050Sstevel@tonic-gate 		dflag = rflag = DEF_DEFINED;
7060Sstevel@tonic-gate 
7070Sstevel@tonic-gate 	/*
7080Sstevel@tonic-gate 	 * Open the input file and initialize the elf interface.
7090Sstevel@tonic-gate 	 */
7100Sstevel@tonic-gate 	for (; optind < argc; optind++) {
7110Sstevel@tonic-gate 		int		derror = 0, nerror = 0,	err;
7120Sstevel@tonic-gate 		const char	*file = argv[optind];
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 		if ((var = open(file, O_RDONLY)) == -1) {
7150Sstevel@tonic-gate 			err = errno;
7160Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN),
7170Sstevel@tonic-gate 			    cname, file, strerror(err));
7180Sstevel@tonic-gate 			error = 1;
7190Sstevel@tonic-gate 			continue;
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 		(void) elf_version(EV_CURRENT);
7220Sstevel@tonic-gate 		if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) {
7230Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname,
7240Sstevel@tonic-gate 			    file, elf_errmsg(elf_errno()));
7250Sstevel@tonic-gate 			error = 1;
7260Sstevel@tonic-gate 			(void) close(var);
7270Sstevel@tonic-gate 			continue;
7280Sstevel@tonic-gate 		}
7290Sstevel@tonic-gate 		if (elf_kind(elf) != ELF_K_ELF) {
7300Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname,
7310Sstevel@tonic-gate 			    file);
7320Sstevel@tonic-gate 			error = 1;
7330Sstevel@tonic-gate 			(void) close(var);
7340Sstevel@tonic-gate 			(void) elf_end(elf);
7350Sstevel@tonic-gate 			continue;
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 		if (gelf_getehdr(elf, &ehdr) == NULL) {
7380Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname,
7390Sstevel@tonic-gate 			    file, elf_errmsg(elf_errno()));
7400Sstevel@tonic-gate 			error = 1;
7410Sstevel@tonic-gate 			(void) close(var);
7420Sstevel@tonic-gate 			(void) elf_end(elf);
7430Sstevel@tonic-gate 			continue;
7440Sstevel@tonic-gate 		}
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 		/*
7470Sstevel@tonic-gate 		 *  Obtain the .shstrtab data buffer to provide the required
7480Sstevel@tonic-gate 		 * section name strings.
7490Sstevel@tonic-gate 		 */
7500Sstevel@tonic-gate 		if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) {
7510Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname,
7520Sstevel@tonic-gate 			    file, elf_errmsg(elf_errno()));
7530Sstevel@tonic-gate 			error = 1;
7540Sstevel@tonic-gate 			(void) close(var);
7550Sstevel@tonic-gate 			(void) elf_end(elf);
7560Sstevel@tonic-gate 			continue;
7570Sstevel@tonic-gate 		}
7580Sstevel@tonic-gate 		if ((data = elf_getdata(scn, NULL)) == NULL) {
7590Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname,
7600Sstevel@tonic-gate 			    file, elf_errmsg(elf_errno()));
7610Sstevel@tonic-gate 			error = 1;
7620Sstevel@tonic-gate 			(void) close(var);
7630Sstevel@tonic-gate 			(void) elf_end(elf);
7640Sstevel@tonic-gate 			continue;
7650Sstevel@tonic-gate 		}
7660Sstevel@tonic-gate 		names = data->d_buf;
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 		/*
7690Sstevel@tonic-gate 		 * Fill in the cache descriptor with information for each
7700Sstevel@tonic-gate 		 * section we might need.   We probably only need to save
7710Sstevel@tonic-gate 		 * read-only allocable sections as this is where the version
7720Sstevel@tonic-gate 		 * structures and their associated symbols and strings live.
7730Sstevel@tonic-gate 		 * However, God knows what someone can do with a mapfile, and
7740Sstevel@tonic-gate 		 * as elf_begin has already gone through all the overhead we
7750Sstevel@tonic-gate 		 * might as well set up the cache for every section.
7760Sstevel@tonic-gate 		 */
7770Sstevel@tonic-gate 		if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == 0) {
7780Sstevel@tonic-gate 			int err = errno;
7790Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname,
7800Sstevel@tonic-gate 			    file, strerror(err));
7810Sstevel@tonic-gate 			exit(1);
7820Sstevel@tonic-gate 		}
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 		_cache_def = _cache_need = _cache_sym = _cache_loc = 0;
7850Sstevel@tonic-gate 		_cache = cache;
7860Sstevel@tonic-gate 		_cache++;
7870Sstevel@tonic-gate 		for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) {
7880Sstevel@tonic-gate 			if (gelf_getshdr(scn, &shdr) == NULL) {
7890Sstevel@tonic-gate 				(void) fprintf(stderr,
7900Sstevel@tonic-gate 				    MSG_ORIG(MSG_ELF_GETSHDR), cname, file,
7910Sstevel@tonic-gate 				    elf_errmsg(elf_errno()));
7920Sstevel@tonic-gate 				error = 1;
7930Sstevel@tonic-gate 				continue;
7940Sstevel@tonic-gate 			}
7950Sstevel@tonic-gate 			if ((_cache->c_data = elf_getdata(scn, NULL)) ==
7960Sstevel@tonic-gate 			    NULL) {
7970Sstevel@tonic-gate 				(void) fprintf(stderr,
7980Sstevel@tonic-gate 				    MSG_ORIG(MSG_ELF_GETDATA), cname, file,
7990Sstevel@tonic-gate 				    elf_errmsg(elf_errno()));
8000Sstevel@tonic-gate 				error = 1;
8010Sstevel@tonic-gate 				continue;
8020Sstevel@tonic-gate 			}
8030Sstevel@tonic-gate 			_cache->c_scn = scn;
8040Sstevel@tonic-gate 			_cache->c_name = names + shdr.sh_name;
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 			/*
8070Sstevel@tonic-gate 			 * Remember the version sections and symbol table.
8080Sstevel@tonic-gate 			 */
8090Sstevel@tonic-gate 			if ((shdr.sh_type == SHT_SUNW_verdef) && dflag)
8100Sstevel@tonic-gate 				_cache_def = _cache;
8110Sstevel@tonic-gate 			else if ((shdr.sh_type == SHT_SUNW_verneed) && rflag)
8120Sstevel@tonic-gate 				_cache_need = _cache;
8130Sstevel@tonic-gate 			else if ((shdr.sh_type == SHT_SUNW_versym) && sflag)
8140Sstevel@tonic-gate 				_cache_sym = _cache;
8150Sstevel@tonic-gate 			else if ((shdr.sh_type == SHT_SYMTAB) && lflag)
8160Sstevel@tonic-gate 				_cache_loc = _cache;
8170Sstevel@tonic-gate 		}
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 		/*
8200Sstevel@tonic-gate 		 * Before printing anything out determine if any warnings are
8210Sstevel@tonic-gate 		 * necessary.
8220Sstevel@tonic-gate 		 */
8230Sstevel@tonic-gate 		if (lflag && (_cache_loc == 0)) {
8240Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS),
8250Sstevel@tonic-gate 			    cname, file);
8260Sstevel@tonic-gate 			(void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB));
8270Sstevel@tonic-gate 		}
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 		/*
8300Sstevel@tonic-gate 		 * If there is more than one input file, and we're not printing
8310Sstevel@tonic-gate 		 * one-line output, display the filename being processed.
8320Sstevel@tonic-gate 		 */
8330Sstevel@tonic-gate 		if ((nfile > 1) && !oflag)
8340Sstevel@tonic-gate 			(void) printf("%s:\n", file);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		/*
8370Sstevel@tonic-gate 		 * Print the files version needed sections.
8380Sstevel@tonic-gate 		 */
8390Sstevel@tonic-gate 		if (_cache_need)
8400Sstevel@tonic-gate 			nerror = gvers_need(cache, _cache_need, file, name);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 		/*
8430Sstevel@tonic-gate 		 * Print the files version definition sections.
8440Sstevel@tonic-gate 		 */
8450Sstevel@tonic-gate 		if (_cache_def)
8460Sstevel@tonic-gate 			derror = gvers_def(cache, _cache_def, _cache_sym,
8470Sstevel@tonic-gate 			    file, name);
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 		/*
8500Sstevel@tonic-gate 		 * Print any local symbol reductions.
8510Sstevel@tonic-gate 		 */
8520Sstevel@tonic-gate 		if (_cache_loc)
8530Sstevel@tonic-gate 			sym_local(cache, _cache_loc, file);
8540Sstevel@tonic-gate 
8550Sstevel@tonic-gate 		/*
8560Sstevel@tonic-gate 		 * Determine the error return.  There are three conditions that
8570Sstevel@tonic-gate 		 * may produce an error (a non-zero return):
8580Sstevel@tonic-gate 		 *
8590Sstevel@tonic-gate 		 *  o	if the user specified -d and no version definitions
8600Sstevel@tonic-gate 		 *	were found.
8610Sstevel@tonic-gate 		 *
8620Sstevel@tonic-gate 		 *  o	if the user specified -r and no version requirements
8630Sstevel@tonic-gate 		 *	were found.
8640Sstevel@tonic-gate 		 *
8650Sstevel@tonic-gate 		 *  o	if the user specified neither -d or -r, (thus both are
8660Sstevel@tonic-gate 		 *	enabled by default), and no version definitions or
8670Sstevel@tonic-gate 		 *	version dependencies were found.
8680Sstevel@tonic-gate 		 */
8690Sstevel@tonic-gate 		if (((dflag == USR_DEFINED) && (derror == 0)) ||
8700Sstevel@tonic-gate 		    ((rflag == USR_DEFINED) && (nerror == 0)) ||
8710Sstevel@tonic-gate 		    (rflag && dflag && (derror == 0) && (nerror == 0)))
8720Sstevel@tonic-gate 			error = 1;
8730Sstevel@tonic-gate 
8740Sstevel@tonic-gate 		(void) close(var);
8750Sstevel@tonic-gate 		(void) elf_end(elf);
8760Sstevel@tonic-gate 		free(cache);
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 	return (error);
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate const char *
8820Sstevel@tonic-gate _pvs_msg(Msg mid)
8830Sstevel@tonic-gate {
8840Sstevel@tonic-gate 	return (gettext(MSG_ORIG(mid)));
8850Sstevel@tonic-gate }
886