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