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 /* 23*7682SAli.Bahrami@Sun.COM * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate /* 280Sstevel@tonic-gate * Analyze the versioning information within a file. 290Sstevel@tonic-gate * 300Sstevel@tonic-gate * -C demangle C++ symbol names. 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * -d dump version definitions. 330Sstevel@tonic-gate * 34*7682SAli.Bahrami@Sun.COM * -l print reduced (local) symbols. Implies -s. 350Sstevel@tonic-gate * 360Sstevel@tonic-gate * -n normalize any version definitions. 370Sstevel@tonic-gate * 380Sstevel@tonic-gate * -o dump output in one-line fashion (more suitable for grep'ing 390Sstevel@tonic-gate * and diff'ing). 400Sstevel@tonic-gate * 410Sstevel@tonic-gate * -r dump the version requirements on library dependencies 420Sstevel@tonic-gate * 430Sstevel@tonic-gate * -s display the symbols associated with each version definition. 440Sstevel@tonic-gate * 450Sstevel@tonic-gate * -v verbose output. With the -r and -d options any WEAK attribute 460Sstevel@tonic-gate * is displayed. With the -d option, any version inheritance, 47*7682SAli.Bahrami@Sun.COM * and the base version are displayed. With the -r option, 48*7682SAli.Bahrami@Sun.COM * WEAK and INFO attributes are displayed. With the -s option 49*7682SAli.Bahrami@Sun.COM * the version symbol is displayed. 50*7682SAli.Bahrami@Sun.COM * 51*7682SAli.Bahrami@Sun.COM * -I index only print the specifed version index, or index range. 520Sstevel@tonic-gate * 530Sstevel@tonic-gate * -N name only print the specifed `name'. 540Sstevel@tonic-gate */ 550Sstevel@tonic-gate #include <fcntl.h> 560Sstevel@tonic-gate #include <stdio.h> 570Sstevel@tonic-gate #include <libelf.h> 580Sstevel@tonic-gate #include <link.h> 590Sstevel@tonic-gate #include <stdlib.h> 600Sstevel@tonic-gate #include <string.h> 610Sstevel@tonic-gate #include <unistd.h> 620Sstevel@tonic-gate #include <locale.h> 630Sstevel@tonic-gate #include <errno.h> 641618Srie #include <sgs.h> 651618Srie #include <conv.h> 661618Srie #include <gelf.h> 671618Srie #include <debug.h> 68*7682SAli.Bahrami@Sun.COM #include <ctype.h> 69*7682SAli.Bahrami@Sun.COM #include <alist.h> 700Sstevel@tonic-gate #include "msg.h" 710Sstevel@tonic-gate 72*7682SAli.Bahrami@Sun.COM /* 73*7682SAli.Bahrami@Sun.COM * Define Alist initialization sizes. 74*7682SAli.Bahrami@Sun.COM */ 75*7682SAli.Bahrami@Sun.COM #define AL_CNT_MATCH_LIST 5 /* match_list initial alist count */ 76*7682SAli.Bahrami@Sun.COM #define AL_CNT_GVER_DESC 25 /* version tracking descriptors */ 770Sstevel@tonic-gate 780Sstevel@tonic-gate typedef struct cache { 790Sstevel@tonic-gate Elf_Scn *c_scn; 800Sstevel@tonic-gate Elf_Data *c_data; 810Sstevel@tonic-gate char *c_name; 820Sstevel@tonic-gate } Cache; 830Sstevel@tonic-gate 840Sstevel@tonic-gate typedef struct gver_desc { 850Sstevel@tonic-gate const char *vd_name; 860Sstevel@tonic-gate unsigned long vd_hash; 870Sstevel@tonic-gate GElf_Half vd_ndx; 880Sstevel@tonic-gate GElf_Half vd_flags; 89*7682SAli.Bahrami@Sun.COM APlist *vd_deps; 900Sstevel@tonic-gate } GVer_desc; 910Sstevel@tonic-gate 92*7682SAli.Bahrami@Sun.COM /* Versym related data used by gvers_syms() */ 93*7682SAli.Bahrami@Sun.COM typedef struct { 94*7682SAli.Bahrami@Sun.COM GElf_Versym *vsd_vsp; /* ptr to versym data */ 95*7682SAli.Bahrami@Sun.COM Elf_Data *vsd_sym_data; /* ptr to symtab data */ 96*7682SAli.Bahrami@Sun.COM Word vsd_symn; /* # of symbols in symtab */ 97*7682SAli.Bahrami@Sun.COM const char *vsd_strs; /* string table data */ 98*7682SAli.Bahrami@Sun.COM } Gver_sym_data; 99*7682SAli.Bahrami@Sun.COM 100*7682SAli.Bahrami@Sun.COM /* 101*7682SAli.Bahrami@Sun.COM * Type used to manage -I and -N options: 102*7682SAli.Bahrami@Sun.COM * 103*7682SAli.Bahrami@Sun.COM * The -I option specifies a VERSYM index, or index range. The 104*7682SAli.Bahrami@Sun.COM * result is to select the VERDEF or VERNEED records with 105*7682SAli.Bahrami@Sun.COM * indexes that match those given. 106*7682SAli.Bahrami@Sun.COM * 107*7682SAli.Bahrami@Sun.COM * -N options come in two forms: 108*7682SAli.Bahrami@Sun.COM * 109*7682SAli.Bahrami@Sun.COM * 1) name 110*7682SAli.Bahrami@Sun.COM * 2) needobj (version) 111*7682SAli.Bahrami@Sun.COM * 112*7682SAli.Bahrami@Sun.COM * The meaning of the first case depends on the type of 113*7682SAli.Bahrami@Sun.COM * version record being matched: 114*7682SAli.Bahrami@Sun.COM * 115*7682SAli.Bahrami@Sun.COM * VERDEF - name is the name of a version defined 116*7682SAli.Bahrami@Sun.COM * by the object being processed (i.e. SUNW_1.1). 117*7682SAli.Bahrami@Sun.COM * 118*7682SAli.Bahrami@Sun.COM * VERNEED - name is the name of the object file 119*7682SAli.Bahrami@Sun.COM * on which the dependency exists (i.e. libc.so.1). 120*7682SAli.Bahrami@Sun.COM * 121*7682SAli.Bahrami@Sun.COM * -N options of the second form only apply to VERNEED records. 122*7682SAli.Bahrami@Sun.COM * They are used to specify a version from a needed object. 123*7682SAli.Bahrami@Sun.COM */ 124*7682SAli.Bahrami@Sun.COM /* match_opt_t is used to note which match option was used */ 125*7682SAli.Bahrami@Sun.COM typedef enum { 126*7682SAli.Bahrami@Sun.COM MATCH_OPT_NAME, /* Record contains a name */ 127*7682SAli.Bahrami@Sun.COM MATCH_OPT_NEED_VER, /* Record contains needed object and version */ 128*7682SAli.Bahrami@Sun.COM MATCH_OPT_NDX, /* Record contains a single index */ 129*7682SAli.Bahrami@Sun.COM MATCH_OPT_RANGE, /* Record contains an index range */ 130*7682SAli.Bahrami@Sun.COM } match_opt_t; 131*7682SAli.Bahrami@Sun.COM 132*7682SAli.Bahrami@Sun.COM typedef struct { 133*7682SAli.Bahrami@Sun.COM match_opt_t opt_type; 134*7682SAli.Bahrami@Sun.COM union { 135*7682SAli.Bahrami@Sun.COM struct { 136*7682SAli.Bahrami@Sun.COM const char *version; /* MATCH_OPT_{NAME|NEED_VER} */ 137*7682SAli.Bahrami@Sun.COM const char *needobj; /* MATCH_OPT_NEED_VER only */ 138*7682SAli.Bahrami@Sun.COM } name; 139*7682SAli.Bahrami@Sun.COM struct { 140*7682SAli.Bahrami@Sun.COM int start; /* MATCH_OPT_{NDX|RANGE} */ 141*7682SAli.Bahrami@Sun.COM int end; /* MATCH_OPT_RANGE only) */ 142*7682SAli.Bahrami@Sun.COM } ndx; 143*7682SAli.Bahrami@Sun.COM } value; 144*7682SAli.Bahrami@Sun.COM } match_rec_t; 145*7682SAli.Bahrami@Sun.COM 146*7682SAli.Bahrami@Sun.COM 147*7682SAli.Bahrami@Sun.COM 1480Sstevel@tonic-gate static const char *cname; 1490Sstevel@tonic-gate static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag; 150*7682SAli.Bahrami@Sun.COM static Alist *match_list; 1510Sstevel@tonic-gate 152*7682SAli.Bahrami@Sun.COM /* Used to track whether an option defaulted to on, or was explicitly set */ 1530Sstevel@tonic-gate #define DEF_DEFINED 1 1540Sstevel@tonic-gate #define USR_DEFINED 2 1550Sstevel@tonic-gate 1560Sstevel@tonic-gate /* 1570Sstevel@tonic-gate * Determine whether a symbol name should be demangled. 1580Sstevel@tonic-gate */ 1590Sstevel@tonic-gate static const char * 1600Sstevel@tonic-gate demangle(const char *name) 1610Sstevel@tonic-gate { 1620Sstevel@tonic-gate if (Cflag) 1631618Srie return (Elf_demangle_name(name)); 1640Sstevel@tonic-gate else 1650Sstevel@tonic-gate return (name); 1660Sstevel@tonic-gate } 1670Sstevel@tonic-gate 1680Sstevel@tonic-gate /* 169*7682SAli.Bahrami@Sun.COM * Append an item to the specified list, and return a pointer to the list 170*7682SAli.Bahrami@Sun.COM * node created. 171*7682SAli.Bahrami@Sun.COM * 172*7682SAli.Bahrami@Sun.COM * exit: 173*7682SAli.Bahrami@Sun.COM * On success, a new list node is created and the item is 174*7682SAli.Bahrami@Sun.COM * added to the list. On failure, a fatal error is issued 175*7682SAli.Bahrami@Sun.COM * and the process exits. 176*7682SAli.Bahrami@Sun.COM */ 177*7682SAli.Bahrami@Sun.COM static void 178*7682SAli.Bahrami@Sun.COM pvs_aplist_append(APlist **lst, const void *item, const char *file) 179*7682SAli.Bahrami@Sun.COM { 180*7682SAli.Bahrami@Sun.COM if (aplist_append(lst, item, AL_CNT_GVER_DESC) == NULL) { 181*7682SAli.Bahrami@Sun.COM int err = errno; 182*7682SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file, 183*7682SAli.Bahrami@Sun.COM strerror(err)); 184*7682SAli.Bahrami@Sun.COM exit(1); 185*7682SAli.Bahrami@Sun.COM } 186*7682SAli.Bahrami@Sun.COM } 187*7682SAli.Bahrami@Sun.COM 188*7682SAli.Bahrami@Sun.COM /* 189*7682SAli.Bahrami@Sun.COM * Add an entry to match_list for use by match(). This routine is for 190*7682SAli.Bahrami@Sun.COM * use during getopt() processing. 191*7682SAli.Bahrami@Sun.COM * 192*7682SAli.Bahrami@Sun.COM * entry: 193*7682SAli.Bahrami@Sun.COM * opt - One of 'N' or 'I', indicating the option 194*7682SAli.Bahrami@Sun.COM * str - Value string corresponding to opt 195*7682SAli.Bahrami@Sun.COM * 196*7682SAli.Bahrami@Sun.COM * exit: 197*7682SAli.Bahrami@Sun.COM * The new match record has been added. On error, a fatal 198*7682SAli.Bahrami@Sun.COM * error is issued and and the process exits. 199*7682SAli.Bahrami@Sun.COM */ 200*7682SAli.Bahrami@Sun.COM static void 201*7682SAli.Bahrami@Sun.COM add_match_record(int opt, const char *str) 202*7682SAli.Bahrami@Sun.COM { 203*7682SAli.Bahrami@Sun.COM /* 204*7682SAli.Bahrami@Sun.COM * Macros for removing leading and trailing whitespace: 205*7682SAli.Bahrami@Sun.COM * WS_SKIP - Advance _str without passing the NULL termination, 206*7682SAli.Bahrami@Sun.COM * until the first character is not whitespace. 207*7682SAli.Bahrami@Sun.COM * WS_SKIP_LIMIT - Advance _str without passing _limit, 208*7682SAli.Bahrami@Sun.COM * until the first character is not whitespace. 209*7682SAli.Bahrami@Sun.COM * WS_RSKIP_LIMIT - Move _tail back without passing _str, 210*7682SAli.Bahrami@Sun.COM * until the character before it is not whitespace. 211*7682SAli.Bahrami@Sun.COM * Write a NULL termination at that point. 212*7682SAli.Bahrami@Sun.COM */ 213*7682SAli.Bahrami@Sun.COM #define WS_SKIP(_str) for (; *(_str) && isspace(*(_str)); (_str)++) 214*7682SAli.Bahrami@Sun.COM #define WS_SKIP_LIMIT(_str, _limit) \ 215*7682SAli.Bahrami@Sun.COM while (((_str) < s2) && isspace(*(_str))) \ 216*7682SAli.Bahrami@Sun.COM (_str)++ 217*7682SAli.Bahrami@Sun.COM #define WS_RSKIP_LIMIT(_str, _tail) \ 218*7682SAli.Bahrami@Sun.COM while (((_tail) > (_str)) && isspace(*((_tail) - 1))) \ 219*7682SAli.Bahrami@Sun.COM (_tail)--; \ 220*7682SAli.Bahrami@Sun.COM *(_tail) = '\0' 221*7682SAli.Bahrami@Sun.COM 222*7682SAli.Bahrami@Sun.COM 223*7682SAli.Bahrami@Sun.COM match_rec_t *rec; 224*7682SAli.Bahrami@Sun.COM char *lstr, *s1, *s2; 225*7682SAli.Bahrami@Sun.COM 226*7682SAli.Bahrami@Sun.COM rec = alist_append(&match_list, NULL, sizeof (match_rec_t), 227*7682SAli.Bahrami@Sun.COM AL_CNT_MATCH_LIST); 228*7682SAli.Bahrami@Sun.COM if (rec == NULL) { 229*7682SAli.Bahrami@Sun.COM int err = errno; 230*7682SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 231*7682SAli.Bahrami@Sun.COM MSG_INTL(MSG_STR_MATCH_RECORD), strerror(err)); 232*7682SAli.Bahrami@Sun.COM exit(1); 233*7682SAli.Bahrami@Sun.COM } 234*7682SAli.Bahrami@Sun.COM 235*7682SAli.Bahrami@Sun.COM if (opt == 'N') { 236*7682SAli.Bahrami@Sun.COM if ((lstr = strdup(str)) == NULL) { 237*7682SAli.Bahrami@Sun.COM int err = errno; 238*7682SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 239*7682SAli.Bahrami@Sun.COM cname, MSG_INTL(MSG_STR_MATCH_RECORD), 240*7682SAli.Bahrami@Sun.COM strerror(err)); 241*7682SAli.Bahrami@Sun.COM exit(1); 242*7682SAli.Bahrami@Sun.COM } 243*7682SAli.Bahrami@Sun.COM 244*7682SAli.Bahrami@Sun.COM /* Strip leading/trailing whitespace */ 245*7682SAli.Bahrami@Sun.COM s2 = lstr + strlen(lstr); 246*7682SAli.Bahrami@Sun.COM WS_SKIP_LIMIT(lstr, s2); 247*7682SAli.Bahrami@Sun.COM WS_RSKIP_LIMIT(lstr, s2); 248*7682SAli.Bahrami@Sun.COM 249*7682SAli.Bahrami@Sun.COM /* Assume this is a plain string */ 250*7682SAli.Bahrami@Sun.COM rec->opt_type = MATCH_OPT_NAME; 251*7682SAli.Bahrami@Sun.COM rec->value.name.version = lstr; 252*7682SAli.Bahrami@Sun.COM 253*7682SAli.Bahrami@Sun.COM /* 254*7682SAli.Bahrami@Sun.COM * If s2 points at a closing paren, then this might 255*7682SAli.Bahrami@Sun.COM * be a MATCH_OPT_NEED_VER case. Otherwise we're done. 256*7682SAli.Bahrami@Sun.COM */ 257*7682SAli.Bahrami@Sun.COM if ((s2 == lstr) || (*(s2 - 1) != ')')) 258*7682SAli.Bahrami@Sun.COM return; 259*7682SAli.Bahrami@Sun.COM 260*7682SAli.Bahrami@Sun.COM /* We have a closing paren. Locate the opening one. */ 261*7682SAli.Bahrami@Sun.COM for (s1 = lstr; *s1 && (*s1 != '('); s1++) 262*7682SAli.Bahrami@Sun.COM ; 263*7682SAli.Bahrami@Sun.COM if (*s1 != '(') 264*7682SAli.Bahrami@Sun.COM return; 265*7682SAli.Bahrami@Sun.COM 266*7682SAli.Bahrami@Sun.COM rec->opt_type = MATCH_OPT_NEED_VER; 267*7682SAli.Bahrami@Sun.COM rec->value.name.needobj = lstr; 268*7682SAli.Bahrami@Sun.COM rec->value.name.version = s1 + 1; 269*7682SAli.Bahrami@Sun.COM s2--; /* Points at closing paren */ 270*7682SAli.Bahrami@Sun.COM 271*7682SAli.Bahrami@Sun.COM /* Remove whitespace from head/tail of version */ 272*7682SAli.Bahrami@Sun.COM WS_SKIP_LIMIT(rec->value.name.version, s2); 273*7682SAli.Bahrami@Sun.COM WS_RSKIP_LIMIT(rec->value.name.version, s2); 274*7682SAli.Bahrami@Sun.COM 275*7682SAli.Bahrami@Sun.COM /* Terminate needobj, skipping trailing whitespace */ 276*7682SAli.Bahrami@Sun.COM WS_RSKIP_LIMIT(rec->value.name.needobj, s1); 277*7682SAli.Bahrami@Sun.COM 278*7682SAli.Bahrami@Sun.COM return; 279*7682SAli.Bahrami@Sun.COM } 280*7682SAli.Bahrami@Sun.COM 281*7682SAli.Bahrami@Sun.COM 282*7682SAli.Bahrami@Sun.COM /* If we get here, we are looking at a -I index option */ 283*7682SAli.Bahrami@Sun.COM rec->value.ndx.start = strtol(str, &s2, 10); 284*7682SAli.Bahrami@Sun.COM /* Value must use some of the input, and be positive */ 285*7682SAli.Bahrami@Sun.COM if ((str == s2) || (rec->value.ndx.start < 1)) 286*7682SAli.Bahrami@Sun.COM goto syntax_error; 287*7682SAli.Bahrami@Sun.COM str = s2; 288*7682SAli.Bahrami@Sun.COM 289*7682SAli.Bahrami@Sun.COM WS_SKIP(str); 290*7682SAli.Bahrami@Sun.COM if (*str != ':') { 291*7682SAli.Bahrami@Sun.COM rec->opt_type = MATCH_OPT_NDX; 292*7682SAli.Bahrami@Sun.COM } else { 293*7682SAli.Bahrami@Sun.COM str++; /* Skip the ':' */ 294*7682SAli.Bahrami@Sun.COM rec->opt_type = MATCH_OPT_RANGE; 295*7682SAli.Bahrami@Sun.COM WS_SKIP(str); 296*7682SAli.Bahrami@Sun.COM if (*str == '\0') { 297*7682SAli.Bahrami@Sun.COM rec->value.ndx.end = -1; /* Indicates "to end" */ 298*7682SAli.Bahrami@Sun.COM } else { 299*7682SAli.Bahrami@Sun.COM rec->value.ndx.end = strtol(str, &s2, 10); 300*7682SAli.Bahrami@Sun.COM if ((str == s2) || (rec->value.ndx.end < 0)) 301*7682SAli.Bahrami@Sun.COM goto syntax_error; 302*7682SAli.Bahrami@Sun.COM str = s2; 303*7682SAli.Bahrami@Sun.COM WS_SKIP(str); 304*7682SAli.Bahrami@Sun.COM } 305*7682SAli.Bahrami@Sun.COM } 306*7682SAli.Bahrami@Sun.COM 307*7682SAli.Bahrami@Sun.COM /* If we are successful, there is nothing left to parse */ 308*7682SAli.Bahrami@Sun.COM if (*str == '\0') 309*7682SAli.Bahrami@Sun.COM return; 310*7682SAli.Bahrami@Sun.COM 311*7682SAli.Bahrami@Sun.COM /* 312*7682SAli.Bahrami@Sun.COM * If we get here, there is leftover input. Fall through 313*7682SAli.Bahrami@Sun.COM * to issue a syntax error. 314*7682SAli.Bahrami@Sun.COM */ 315*7682SAli.Bahrami@Sun.COM syntax_error: 316*7682SAli.Bahrami@Sun.COM (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 317*7682SAli.Bahrami@Sun.COM exit(1); 318*7682SAli.Bahrami@Sun.COM 319*7682SAli.Bahrami@Sun.COM #undef WS_SKIP 320*7682SAli.Bahrami@Sun.COM #undef WS_SKIP_LIMIT 321*7682SAli.Bahrami@Sun.COM #undef WS_RSKIP_LIMIT 322*7682SAli.Bahrami@Sun.COM } 323*7682SAli.Bahrami@Sun.COM 324*7682SAli.Bahrami@Sun.COM /* 325*7682SAli.Bahrami@Sun.COM * Returns True (1) if the version with the given name or index should 326*7682SAli.Bahrami@Sun.COM * be displayed, and False (0) if it should not be. 327*7682SAli.Bahrami@Sun.COM * 328*7682SAli.Bahrami@Sun.COM * entry: 329*7682SAli.Bahrami@Sun.COM * needobj - NULL for VERDEF records, the name of the 330*7682SAli.Bahrami@Sun.COM * needed object for VERNEED. 331*7682SAli.Bahrami@Sun.COM * version - NULL, or needed version 332*7682SAli.Bahrami@Sun.COM * ndx - Versym index of version under consideration, or a value less 333*7682SAli.Bahrami@Sun.COM * than 1 to indicate that no valid index is given. 334*7682SAli.Bahrami@Sun.COM * 335*7682SAli.Bahrami@Sun.COM * exit: 336*7682SAli.Bahrami@Sun.COM * True will be returned if the given name/index matches those given 337*7682SAli.Bahrami@Sun.COM * by one of the -I or -N command line options, or if no such option 338*7682SAli.Bahrami@Sun.COM * was used in the command invocation. 339*7682SAli.Bahrami@Sun.COM */ 340*7682SAli.Bahrami@Sun.COM int 341*7682SAli.Bahrami@Sun.COM match(const char *needobj, const char *version, int ndx) 342*7682SAli.Bahrami@Sun.COM { 343*7682SAli.Bahrami@Sun.COM Aliste _idx; 344*7682SAli.Bahrami@Sun.COM match_rec_t *rec; 345*7682SAli.Bahrami@Sun.COM const char *str; 346*7682SAli.Bahrami@Sun.COM 347*7682SAli.Bahrami@Sun.COM /* If there is no match list, then we approve everything */ 348*7682SAli.Bahrami@Sun.COM if (alist_nitems(match_list) == 0) 349*7682SAli.Bahrami@Sun.COM return (1); 350*7682SAli.Bahrami@Sun.COM 351*7682SAli.Bahrami@Sun.COM /* Run through the match records and check for a hit */ 352*7682SAli.Bahrami@Sun.COM for (ALIST_TRAVERSE(match_list, _idx, rec)) { 353*7682SAli.Bahrami@Sun.COM switch (rec->opt_type) { 354*7682SAli.Bahrami@Sun.COM case MATCH_OPT_NAME: 355*7682SAli.Bahrami@Sun.COM if (needobj) 356*7682SAli.Bahrami@Sun.COM str = needobj; 357*7682SAli.Bahrami@Sun.COM else if (version) 358*7682SAli.Bahrami@Sun.COM str = version; 359*7682SAli.Bahrami@Sun.COM else 360*7682SAli.Bahrami@Sun.COM break; 361*7682SAli.Bahrami@Sun.COM if (strcmp(rec->value.name.version, str) == 0) 362*7682SAli.Bahrami@Sun.COM return (1); 363*7682SAli.Bahrami@Sun.COM break; 364*7682SAli.Bahrami@Sun.COM case MATCH_OPT_NEED_VER: 365*7682SAli.Bahrami@Sun.COM if (needobj && version && 366*7682SAli.Bahrami@Sun.COM (strcmp(rec->value.name.needobj, needobj) == 0) && 367*7682SAli.Bahrami@Sun.COM (strcmp(rec->value.name.version, version) == 0)) 368*7682SAli.Bahrami@Sun.COM return (1); 369*7682SAli.Bahrami@Sun.COM break; 370*7682SAli.Bahrami@Sun.COM case MATCH_OPT_NDX: 371*7682SAli.Bahrami@Sun.COM if ((ndx > 0) && (ndx == rec->value.ndx.start)) 372*7682SAli.Bahrami@Sun.COM return (1); 373*7682SAli.Bahrami@Sun.COM break; 374*7682SAli.Bahrami@Sun.COM case MATCH_OPT_RANGE: 375*7682SAli.Bahrami@Sun.COM /* 376*7682SAli.Bahrami@Sun.COM * A range end value less than 0 means that any value 377*7682SAli.Bahrami@Sun.COM * above the start is acceptible. 378*7682SAli.Bahrami@Sun.COM */ 379*7682SAli.Bahrami@Sun.COM if ((ndx > 0) && 380*7682SAli.Bahrami@Sun.COM (ndx >= rec->value.ndx.start) && 381*7682SAli.Bahrami@Sun.COM ((rec->value.ndx.end < 0) || 382*7682SAli.Bahrami@Sun.COM (ndx <= rec->value.ndx.end))) 383*7682SAli.Bahrami@Sun.COM return (1); 384*7682SAli.Bahrami@Sun.COM break; 385*7682SAli.Bahrami@Sun.COM } 386*7682SAli.Bahrami@Sun.COM } 387*7682SAli.Bahrami@Sun.COM 388*7682SAli.Bahrami@Sun.COM /* Nothing matched */ 389*7682SAli.Bahrami@Sun.COM return (0); 390*7682SAli.Bahrami@Sun.COM } 391*7682SAli.Bahrami@Sun.COM 392*7682SAli.Bahrami@Sun.COM /* 393*7682SAli.Bahrami@Sun.COM * List the symbols that belong to a specified version 394*7682SAli.Bahrami@Sun.COM * 395*7682SAli.Bahrami@Sun.COM * entry: 396*7682SAli.Bahrami@Sun.COM * vsdata - VERSYM related data from the object 397*7682SAli.Bahrami@Sun.COM * vd_ndx - The VERSYM index for symbols to display 398*7682SAli.Bahrami@Sun.COM * vd_name - Version name 399*7682SAli.Bahrami@Sun.COM * needobj - NULL for symbols corresponding to a VERDEF 400*7682SAli.Bahrami@Sun.COM * record. Name of the needed object in the case 401*7682SAli.Bahrami@Sun.COM * of a VERNEED record. 402*7682SAli.Bahrami@Sun.COM * file - Object file 403*7682SAli.Bahrami@Sun.COM */ 404*7682SAli.Bahrami@Sun.COM static void 405*7682SAli.Bahrami@Sun.COM gvers_syms(const Gver_sym_data *vsdata, GElf_Half vd_ndx, 406*7682SAli.Bahrami@Sun.COM const char *vd_name, const char *needobj, const char *file) 407*7682SAli.Bahrami@Sun.COM { 408*7682SAli.Bahrami@Sun.COM GElf_Sym sym; 409*7682SAli.Bahrami@Sun.COM int _symn; 410*7682SAli.Bahrami@Sun.COM 411*7682SAli.Bahrami@Sun.COM for (_symn = 0; _symn < vsdata->vsd_symn; _symn++) { 412*7682SAli.Bahrami@Sun.COM size_t size = 0; 413*7682SAli.Bahrami@Sun.COM const char *name; 414*7682SAli.Bahrami@Sun.COM 415*7682SAli.Bahrami@Sun.COM if (vsdata->vsd_vsp[_symn] != vd_ndx) 416*7682SAli.Bahrami@Sun.COM continue; 417*7682SAli.Bahrami@Sun.COM 418*7682SAli.Bahrami@Sun.COM (void) gelf_getsym(vsdata->vsd_sym_data, _symn, &sym); 419*7682SAli.Bahrami@Sun.COM name = demangle(vsdata->vsd_strs + sym.st_name); 420*7682SAli.Bahrami@Sun.COM 421*7682SAli.Bahrami@Sun.COM /* 422*7682SAli.Bahrami@Sun.COM * Symbols that reference a VERDEF record 423*7682SAli.Bahrami@Sun.COM * have some extra details to handle. 424*7682SAli.Bahrami@Sun.COM */ 425*7682SAli.Bahrami@Sun.COM if (needobj == NULL) { 426*7682SAli.Bahrami@Sun.COM /* 427*7682SAli.Bahrami@Sun.COM * For data symbols defined by this object, 428*7682SAli.Bahrami@Sun.COM * determine the size. 429*7682SAli.Bahrami@Sun.COM */ 430*7682SAli.Bahrami@Sun.COM if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) || 431*7682SAli.Bahrami@Sun.COM (GELF_ST_TYPE(sym.st_info) == STT_COMMON) || 432*7682SAli.Bahrami@Sun.COM (GELF_ST_TYPE(sym.st_info) == STT_TLS)) 433*7682SAli.Bahrami@Sun.COM size = (size_t)sym.st_size; 434*7682SAli.Bahrami@Sun.COM 435*7682SAli.Bahrami@Sun.COM /* 436*7682SAli.Bahrami@Sun.COM * Only output the version symbol when the verbose 437*7682SAli.Bahrami@Sun.COM * flag is used. 438*7682SAli.Bahrami@Sun.COM */ 439*7682SAli.Bahrami@Sun.COM if (!vflag && (sym.st_shndx == SHN_ABS) && 440*7682SAli.Bahrami@Sun.COM (strcmp(name, vd_name) == 0)) 441*7682SAli.Bahrami@Sun.COM continue; 442*7682SAli.Bahrami@Sun.COM } 443*7682SAli.Bahrami@Sun.COM 444*7682SAli.Bahrami@Sun.COM if (oflag) { 445*7682SAli.Bahrami@Sun.COM if (needobj == NULL) 446*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SYM_OFIL), 447*7682SAli.Bahrami@Sun.COM file, vd_name); 448*7682SAli.Bahrami@Sun.COM else 449*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SYM_NEED_OFIL), 450*7682SAli.Bahrami@Sun.COM file, needobj, vd_name); 451*7682SAli.Bahrami@Sun.COM 452*7682SAli.Bahrami@Sun.COM if (size) 453*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ_OFLG), 454*7682SAli.Bahrami@Sun.COM name, (ulong_t)size); 455*7682SAli.Bahrami@Sun.COM else 456*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SYM_OFLG), name); 457*7682SAli.Bahrami@Sun.COM } else { 458*7682SAli.Bahrami@Sun.COM if (size) 459*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ), name, 460*7682SAli.Bahrami@Sun.COM (ulong_t)size); 461*7682SAli.Bahrami@Sun.COM else 462*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SYM), name); 463*7682SAli.Bahrami@Sun.COM } 464*7682SAli.Bahrami@Sun.COM } 465*7682SAli.Bahrami@Sun.COM } 466*7682SAli.Bahrami@Sun.COM 467*7682SAli.Bahrami@Sun.COM /* 4680Sstevel@tonic-gate * Print any reduced symbols. The convention is that reduced symbols exist as 4690Sstevel@tonic-gate * LOCL entries in the .symtab, between the FILE symbol for the output file and 4700Sstevel@tonic-gate * the first FILE symbol for any input file used to build the output file. 4710Sstevel@tonic-gate */ 4720Sstevel@tonic-gate static void 4730Sstevel@tonic-gate sym_local(Cache *cache, Cache *csym, const char *file) 4740Sstevel@tonic-gate { 4750Sstevel@tonic-gate int symn, _symn, found = 0; 4760Sstevel@tonic-gate GElf_Shdr shdr; 4770Sstevel@tonic-gate GElf_Sym sym; 478*7682SAli.Bahrami@Sun.COM char *strs; 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate (void) gelf_getshdr(csym->c_scn, &shdr); 4810Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 4820Sstevel@tonic-gate /* LINTED */ 4830Sstevel@tonic-gate symn = shdr.sh_info; 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate /* 4860Sstevel@tonic-gate * Verify symtab[1] is the output file symbol. 4870Sstevel@tonic-gate */ 4880Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, 1, &sym); 4890Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_FILE) { 4900Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname, 4910Sstevel@tonic-gate file); 4920Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE), 4930Sstevel@tonic-gate csym->c_name); 4940Sstevel@tonic-gate return; 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate /* 4980Sstevel@tonic-gate * Scan the remaining symbols until the next file symbol is found. 4990Sstevel@tonic-gate */ 5000Sstevel@tonic-gate for (_symn = 2; _symn < symn; _symn++) { 5010Sstevel@tonic-gate const char *name; 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, _symn, &sym); 5040Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) 5050Sstevel@tonic-gate continue; 5060Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 5070Sstevel@tonic-gate break; 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate /* 5100Sstevel@tonic-gate * Its possible that section symbols are followed immediately 5110Sstevel@tonic-gate * by globals. This is the case if an object (filter) is 5120Sstevel@tonic-gate * generated exclusively from mapfile symbol definitions. 5130Sstevel@tonic-gate */ 5140Sstevel@tonic-gate if (GELF_ST_BIND(sym.st_info) != STB_LOCAL) 5150Sstevel@tonic-gate break; 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate name = demangle(strs + sym.st_name); 5180Sstevel@tonic-gate 5190Sstevel@tonic-gate if (oflag) { 520*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_OFLG), 521*7682SAli.Bahrami@Sun.COM file, name); 5220Sstevel@tonic-gate } else { 5230Sstevel@tonic-gate if (found == 0) { 5240Sstevel@tonic-gate found = 1; 525*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_HDR)); 5260Sstevel@tonic-gate } 527*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_LOCSYM), name); 5280Sstevel@tonic-gate } 5290Sstevel@tonic-gate } 5300Sstevel@tonic-gate } 5310Sstevel@tonic-gate 5320Sstevel@tonic-gate /* 533*7682SAli.Bahrami@Sun.COM * Print data from the files VERNEED section. 534*7682SAli.Bahrami@Sun.COM * 535*7682SAli.Bahrami@Sun.COM * If we have been asked to display symbols, then the 536*7682SAli.Bahrami@Sun.COM * output format follows that used for verdef sections, 537*7682SAli.Bahrami@Sun.COM * with each version displayed separately. For instance: 538*7682SAli.Bahrami@Sun.COM * 539*7682SAli.Bahrami@Sun.COM * libc.so.1 (SUNW_1.7): 540*7682SAli.Bahrami@Sun.COM * sym1; 541*7682SAli.Bahrami@Sun.COM * sym2; 542*7682SAli.Bahrami@Sun.COM * libc.so.1 (SUNW_1.9): 543*7682SAli.Bahrami@Sun.COM * sym3; 544*7682SAli.Bahrami@Sun.COM * 545*7682SAli.Bahrami@Sun.COM * If we are not displaying symbols, then a terse format 546*7682SAli.Bahrami@Sun.COM * is used, which combines all the needed versions from 547*7682SAli.Bahrami@Sun.COM * a given object into a single line. In this case, the 548*7682SAli.Bahrami@Sun.COM * versions are shown whether or not they contribute symbols. 549*7682SAli.Bahrami@Sun.COM * 550*7682SAli.Bahrami@Sun.COM * libc.so.1 (SUNW_1.7, SUNW_1.9); 5510Sstevel@tonic-gate */ 5520Sstevel@tonic-gate static int 553*7682SAli.Bahrami@Sun.COM gvers_need(Cache *cache, Cache *need, const Gver_sym_data *vsdata, 554*7682SAli.Bahrami@Sun.COM const char *file) 5550Sstevel@tonic-gate { 5560Sstevel@tonic-gate unsigned int num, _num; 5570Sstevel@tonic-gate char *strs; 5580Sstevel@tonic-gate GElf_Verneed *vnd = need->c_data->d_buf; 5590Sstevel@tonic-gate GElf_Shdr shdr; 5600Sstevel@tonic-gate int error = 0; 561*7682SAli.Bahrami@Sun.COM int show = vflag || (vsdata == NULL) || !oflag; 562*7682SAli.Bahrami@Sun.COM 5630Sstevel@tonic-gate 5640Sstevel@tonic-gate (void) gelf_getshdr(need->c_scn, &shdr); 5650Sstevel@tonic-gate 5660Sstevel@tonic-gate /* 5670Sstevel@tonic-gate * Verify the version revision. We only check the first version 5680Sstevel@tonic-gate * structure as it is assumed all other version structures in this 5690Sstevel@tonic-gate * data section will be of the same revision. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate if (vnd->vn_version > VER_DEF_CURRENT) 5720Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 5730Sstevel@tonic-gate vnd->vn_version, VER_DEF_CURRENT); 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* 5760Sstevel@tonic-gate * Get the data buffer for the associated string table. 5770Sstevel@tonic-gate */ 5780Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 5790Sstevel@tonic-gate num = shdr.sh_info; 5800Sstevel@tonic-gate 5810Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5820Sstevel@tonic-gate vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 583*7682SAli.Bahrami@Sun.COM GElf_Vernaux *vnap; 584*7682SAli.Bahrami@Sun.COM Word ndx; 585*7682SAli.Bahrami@Sun.COM const char *needobj, *dep, *fmt; 586*7682SAli.Bahrami@Sun.COM int started = 0; 5870Sstevel@tonic-gate 588*7682SAli.Bahrami@Sun.COM vnap = (GElf_Vernaux *) ((uintptr_t)vnd + vnd->vn_aux); 589*7682SAli.Bahrami@Sun.COM 590*7682SAli.Bahrami@Sun.COM /* Obtain the needed object file name */ 591*7682SAli.Bahrami@Sun.COM needobj = (char *)(strs + vnd->vn_file); 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate error = 1; 5940Sstevel@tonic-gate 595*7682SAli.Bahrami@Sun.COM /* Process the versions needed from this object */ 596*7682SAli.Bahrami@Sun.COM for (ndx = 0; ndx < vnd->vn_cnt; ndx++, 597*7682SAli.Bahrami@Sun.COM vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) { 598*7682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 599*7682SAli.Bahrami@Sun.COM 600*7682SAli.Bahrami@Sun.COM dep = (char *)(strs + vnap->vna_name); 601*7682SAli.Bahrami@Sun.COM 602*7682SAli.Bahrami@Sun.COM if (!match(needobj, dep, vnap->vna_other)) 603*7682SAli.Bahrami@Sun.COM continue; 6040Sstevel@tonic-gate 605*7682SAli.Bahrami@Sun.COM if (show) { 606*7682SAli.Bahrami@Sun.COM if ((started == 0) || (vsdata != NULL)) { 607*7682SAli.Bahrami@Sun.COM /* 608*7682SAli.Bahrami@Sun.COM * If one-line ouput is called for 609*7682SAli.Bahrami@Sun.COM * display the filename being processed. 610*7682SAli.Bahrami@Sun.COM */ 611*7682SAli.Bahrami@Sun.COM if (oflag && show) 612*7682SAli.Bahrami@Sun.COM (void) printf( 613*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_OFIL), 614*7682SAli.Bahrami@Sun.COM file); 615*7682SAli.Bahrami@Sun.COM 616*7682SAli.Bahrami@Sun.COM (void) printf( 617*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_LIST_BEGIN), 618*7682SAli.Bahrami@Sun.COM needobj); 619*7682SAli.Bahrami@Sun.COM 620*7682SAli.Bahrami@Sun.COM fmt = MSG_ORIG(MSG_FMT_LIST_FIRST); 621*7682SAli.Bahrami@Sun.COM started = 1; 622*7682SAli.Bahrami@Sun.COM } else { 623*7682SAli.Bahrami@Sun.COM fmt = MSG_ORIG(MSG_FMT_LIST_NEXT); 624*7682SAli.Bahrami@Sun.COM } 6250Sstevel@tonic-gate 626*7682SAli.Bahrami@Sun.COM /* 627*7682SAli.Bahrami@Sun.COM * If not showing symbols, only show INFO 628*7682SAli.Bahrami@Sun.COM * versions in verbose mode. They don't 629*7682SAli.Bahrami@Sun.COM * actually contribute to the version 630*7682SAli.Bahrami@Sun.COM * interface as seen by rtld, so listing them 631*7682SAli.Bahrami@Sun.COM * without qualification can be misleading. 632*7682SAli.Bahrami@Sun.COM */ 633*7682SAli.Bahrami@Sun.COM if (vflag || (vsdata != NULL) || 634*7682SAli.Bahrami@Sun.COM (alist_nitems(match_list) != 0) || 635*7682SAli.Bahrami@Sun.COM !(vnap->vna_flags & VER_FLG_INFO)) { 636*7682SAli.Bahrami@Sun.COM (void) printf(fmt, dep); 6370Sstevel@tonic-gate 638*7682SAli.Bahrami@Sun.COM /* Show non-zero flags */ 639*7682SAli.Bahrami@Sun.COM if (vflag && (vnap->vna_flags != 0)) 640*7682SAli.Bahrami@Sun.COM (void) printf( 641*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_VER_FLG), 642*7682SAli.Bahrami@Sun.COM conv_ver_flags( 643*7682SAli.Bahrami@Sun.COM vnap->vna_flags, 644*7682SAli.Bahrami@Sun.COM CONV_FMT_NOBKT, 645*7682SAli.Bahrami@Sun.COM &ver_flags_buf)); 646*7682SAli.Bahrami@Sun.COM } 647*7682SAli.Bahrami@Sun.COM if (vsdata != NULL) 648*7682SAli.Bahrami@Sun.COM (void) printf(oflag ? 649*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_LIST_END_SEM) : 650*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_LIST_END_COL)); 651*7682SAli.Bahrami@Sun.COM } 652*7682SAli.Bahrami@Sun.COM 653*7682SAli.Bahrami@Sun.COM /* 654*7682SAli.Bahrami@Sun.COM * If we are showing symbols, and vna_other is 655*7682SAli.Bahrami@Sun.COM * non-zero, list them here. 656*7682SAli.Bahrami@Sun.COM * 657*7682SAli.Bahrami@Sun.COM * A value of 0 means that this object uses 658*7682SAli.Bahrami@Sun.COM * traditional Solaris versioning rules, under 659*7682SAli.Bahrami@Sun.COM * which VERSYM does not contain indexes to VERNEED 660*7682SAli.Bahrami@Sun.COM * records. In this case, there is nothing to show. 661*7682SAli.Bahrami@Sun.COM */ 662*7682SAli.Bahrami@Sun.COM if (vsdata && (vnap->vna_other > 0)) 663*7682SAli.Bahrami@Sun.COM gvers_syms(vsdata, vnap->vna_other, 664*7682SAli.Bahrami@Sun.COM dep, needobj, file); 6650Sstevel@tonic-gate } 666*7682SAli.Bahrami@Sun.COM if (show && started && (vsdata == NULL)) 667*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_LIST_END_SEM)); 6680Sstevel@tonic-gate } 6690Sstevel@tonic-gate return (error); 6700Sstevel@tonic-gate } 6710Sstevel@tonic-gate 6720Sstevel@tonic-gate /* 673*7682SAli.Bahrami@Sun.COM * Return a GVer_desc descriptor for the given version if one 674*7682SAli.Bahrami@Sun.COM * exists. 675*7682SAli.Bahrami@Sun.COM * 676*7682SAli.Bahrami@Sun.COM * entry: 677*7682SAli.Bahrami@Sun.COM * name - Version name 678*7682SAli.Bahrami@Sun.COM * hash - ELF hash of name 679*7682SAli.Bahrami@Sun.COM * lst - APlist of existing descriptors. 680*7682SAli.Bahrami@Sun.COM * file - Object file containing the version 681*7682SAli.Bahrami@Sun.COM * 682*7682SAli.Bahrami@Sun.COM * exit: 683*7682SAli.Bahrami@Sun.COM * Return the corresponding GVer_desc struct if it 684*7682SAli.Bahrami@Sun.COM * exists, and NULL otherwise. 6850Sstevel@tonic-gate */ 686*7682SAli.Bahrami@Sun.COM static GVer_desc * 687*7682SAli.Bahrami@Sun.COM gvers_find(const char *name, unsigned long hash, APlist *lst) 6880Sstevel@tonic-gate { 689*7682SAli.Bahrami@Sun.COM Aliste idx; 690*7682SAli.Bahrami@Sun.COM GVer_desc *vdp; 6910Sstevel@tonic-gate 692*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(lst, idx, vdp)) 693*7682SAli.Bahrami@Sun.COM if ((vdp->vd_hash == hash) && 694*7682SAli.Bahrami@Sun.COM (strcmp(vdp->vd_name, name) == 0)) 695*7682SAli.Bahrami@Sun.COM return (vdp); 6960Sstevel@tonic-gate 697*7682SAli.Bahrami@Sun.COM return (NULL); 6980Sstevel@tonic-gate } 6990Sstevel@tonic-gate 700*7682SAli.Bahrami@Sun.COM /* 701*7682SAli.Bahrami@Sun.COM * Return a GVer_desc descriptor for the given version. 702*7682SAli.Bahrami@Sun.COM * 703*7682SAli.Bahrami@Sun.COM * entry: 704*7682SAli.Bahrami@Sun.COM * name - Version name 705*7682SAli.Bahrami@Sun.COM * hash - ELF hash of name 706*7682SAli.Bahrami@Sun.COM * lst - List of existing descriptors. 707*7682SAli.Bahrami@Sun.COM * file - Object file containing the version 708*7682SAli.Bahrami@Sun.COM * 709*7682SAli.Bahrami@Sun.COM * exit: 710*7682SAli.Bahrami@Sun.COM * Return the corresponding GVer_desc struct. If the 711*7682SAli.Bahrami@Sun.COM * descriptor does not already exist, it is created. 712*7682SAli.Bahrami@Sun.COM * On error, a fatal error is issued and the process exits. 713*7682SAli.Bahrami@Sun.COM */ 7140Sstevel@tonic-gate static GVer_desc * 715*7682SAli.Bahrami@Sun.COM gvers_desc(const char *name, unsigned long hash, APlist **lst, const char *file) 7160Sstevel@tonic-gate { 7170Sstevel@tonic-gate GVer_desc *vdp; 7180Sstevel@tonic-gate 719*7682SAli.Bahrami@Sun.COM if ((vdp = gvers_find(name, hash, *lst)) == NULL) { 720*7682SAli.Bahrami@Sun.COM if ((vdp = calloc(sizeof (GVer_desc), 1)) == NULL) { 7210Sstevel@tonic-gate int err = errno; 7220Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 7230Sstevel@tonic-gate file, strerror(err)); 7240Sstevel@tonic-gate exit(1); 7250Sstevel@tonic-gate } 7260Sstevel@tonic-gate 7270Sstevel@tonic-gate vdp->vd_name = name; 7280Sstevel@tonic-gate vdp->vd_hash = hash; 7290Sstevel@tonic-gate 730*7682SAli.Bahrami@Sun.COM pvs_aplist_append(lst, vdp, file); 7310Sstevel@tonic-gate } 7320Sstevel@tonic-gate return (vdp); 7330Sstevel@tonic-gate } 7340Sstevel@tonic-gate 735*7682SAli.Bahrami@Sun.COM /* 736*7682SAli.Bahrami@Sun.COM * Insert a version dependency for the given GVer_desc descriptor. 737*7682SAli.Bahrami@Sun.COM * 738*7682SAli.Bahrami@Sun.COM * entry: 739*7682SAli.Bahrami@Sun.COM * name - Dependency version name 740*7682SAli.Bahrami@Sun.COM * hash - ELF hash of name 741*7682SAli.Bahrami@Sun.COM * lst - List of existing descriptors. 742*7682SAli.Bahrami@Sun.COM * vdp - Existing version descriptor to which the dependency 743*7682SAli.Bahrami@Sun.COM * is to be added. 744*7682SAli.Bahrami@Sun.COM * file - Object file containing the version 745*7682SAli.Bahrami@Sun.COM * 746*7682SAli.Bahrami@Sun.COM * exit: 747*7682SAli.Bahrami@Sun.COM * A descriptor for the dependency version is looked up 748*7682SAli.Bahrami@Sun.COM * (created if necessary), and then added to the dependency 749*7682SAli.Bahrami@Sun.COM * list for vdp. Returns the dependency descriptor. On error, 750*7682SAli.Bahrami@Sun.COM * a fatal error is issued and the process exits. 751*7682SAli.Bahrami@Sun.COM */ 7520Sstevel@tonic-gate static GVer_desc * 753*7682SAli.Bahrami@Sun.COM gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, APlist **lst, 7540Sstevel@tonic-gate const char *file) 7550Sstevel@tonic-gate { 7560Sstevel@tonic-gate GVer_desc *_vdp; 7570Sstevel@tonic-gate 758*7682SAli.Bahrami@Sun.COM _vdp = gvers_desc(name, hash, lst, file); 759*7682SAli.Bahrami@Sun.COM pvs_aplist_append(&vdp->vd_deps, _vdp, file); 7600Sstevel@tonic-gate return (vdp); 7610Sstevel@tonic-gate } 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate static void 764*7682SAli.Bahrami@Sun.COM gvers_derefer(GVer_desc *vdp, int weak) 7650Sstevel@tonic-gate { 766*7682SAli.Bahrami@Sun.COM Aliste idx; 767*7682SAli.Bahrami@Sun.COM GVer_desc *_vdp; 7680Sstevel@tonic-gate 7690Sstevel@tonic-gate /* 7700Sstevel@tonic-gate * If the head of the list was a weak then we only clear out 7710Sstevel@tonic-gate * weak dependencies, but if the head of the list was 'strong' 7720Sstevel@tonic-gate * we clear the REFER bit on all dependencies. 7730Sstevel@tonic-gate */ 7740Sstevel@tonic-gate if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak)) 7750Sstevel@tonic-gate vdp->vd_flags &= ~FLG_VER_AVAIL; 7760Sstevel@tonic-gate 777*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) 7780Sstevel@tonic-gate gvers_derefer(_vdp, weak); 7790Sstevel@tonic-gate } 7800Sstevel@tonic-gate 7810Sstevel@tonic-gate 7820Sstevel@tonic-gate static void 783*7682SAli.Bahrami@Sun.COM recurse_syms(const Gver_sym_data *vsdata, GVer_desc *vdp, const char *file) 7840Sstevel@tonic-gate { 785*7682SAli.Bahrami@Sun.COM Aliste idx; 7860Sstevel@tonic-gate GVer_desc *_vdp; 7870Sstevel@tonic-gate 788*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) { 7890Sstevel@tonic-gate if (!oflag) 790*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_TNCO), _vdp->vd_name); 791*7682SAli.Bahrami@Sun.COM gvers_syms(vsdata, _vdp->vd_ndx, _vdp->vd_name, NULL, file); 792*7682SAli.Bahrami@Sun.COM if (aplist_nitems(_vdp->vd_deps) != 0) 793*7682SAli.Bahrami@Sun.COM recurse_syms(vsdata, _vdp, file); 7940Sstevel@tonic-gate } 7950Sstevel@tonic-gate } 7960Sstevel@tonic-gate 7970Sstevel@tonic-gate 7980Sstevel@tonic-gate /* 7990Sstevel@tonic-gate * Print the files version definition sections. 8000Sstevel@tonic-gate */ 8010Sstevel@tonic-gate static int 802*7682SAli.Bahrami@Sun.COM gvers_def(Cache *cache, Cache *def, const Gver_sym_data *vsdata, 803*7682SAli.Bahrami@Sun.COM const char *file) 8040Sstevel@tonic-gate { 8050Sstevel@tonic-gate unsigned int num, _num; 8060Sstevel@tonic-gate char *strs; 8070Sstevel@tonic-gate GElf_Verdef *vdf = def->c_data->d_buf; 8080Sstevel@tonic-gate GElf_Shdr shdr; 809*7682SAli.Bahrami@Sun.COM GVer_desc *vdp, *bvdp = NULL; 810*7682SAli.Bahrami@Sun.COM Aliste idx1; 811*7682SAli.Bahrami@Sun.COM APlist *verdefs = NULL; 8120Sstevel@tonic-gate int error = 0; 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate /* 8150Sstevel@tonic-gate * Verify the version revision. We only check the first version 8160Sstevel@tonic-gate * structure as it is assumed all other version structures in this 8170Sstevel@tonic-gate * data section will be of the same revision. 8180Sstevel@tonic-gate */ 8190Sstevel@tonic-gate if (vdf->vd_version > VER_DEF_CURRENT) { 8200Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 8210Sstevel@tonic-gate vdf->vd_version, VER_DEF_CURRENT); 8220Sstevel@tonic-gate } 8230Sstevel@tonic-gate 8240Sstevel@tonic-gate /* 8250Sstevel@tonic-gate * Get the data buffer for the associated string table. 8260Sstevel@tonic-gate */ 8270Sstevel@tonic-gate (void) gelf_getshdr(def->c_scn, &shdr); 8280Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 8290Sstevel@tonic-gate num = shdr.sh_info; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate /* 8320Sstevel@tonic-gate * Process the version definitions placing each on a version dependency 8330Sstevel@tonic-gate * list. 8340Sstevel@tonic-gate */ 8350Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 8360Sstevel@tonic-gate vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 8370Sstevel@tonic-gate GElf_Half cnt = vdf->vd_cnt; 8380Sstevel@tonic-gate GElf_Half ndx = vdf->vd_ndx; 839*7682SAli.Bahrami@Sun.COM GElf_Verdaux *vdap; 8400Sstevel@tonic-gate const char *_name; 8410Sstevel@tonic-gate 842*7682SAli.Bahrami@Sun.COM vdap = (GElf_Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 843*7682SAli.Bahrami@Sun.COM 8440Sstevel@tonic-gate /* 8450Sstevel@tonic-gate * Determine the version name and any dependencies. 8460Sstevel@tonic-gate */ 8470Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 8480Sstevel@tonic-gate 849*7682SAli.Bahrami@Sun.COM vdp = gvers_desc(_name, elf_hash(_name), &verdefs, file); 8500Sstevel@tonic-gate vdp->vd_ndx = ndx; 8510Sstevel@tonic-gate vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL; 8520Sstevel@tonic-gate 8530Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next); 8540Sstevel@tonic-gate for (cnt--; cnt; cnt--, 8550Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) { 8560Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 8570Sstevel@tonic-gate if (gvers_depend(_name, elf_hash(_name), vdp, 858*7682SAli.Bahrami@Sun.COM &verdefs, file) == NULL) 8590Sstevel@tonic-gate return (0); 8600Sstevel@tonic-gate } 8610Sstevel@tonic-gate 8620Sstevel@tonic-gate /* 8630Sstevel@tonic-gate * Remember the base version for possible later use. 8640Sstevel@tonic-gate */ 8650Sstevel@tonic-gate if (ndx == VER_NDX_GLOBAL) 8660Sstevel@tonic-gate bvdp = vdp; 8670Sstevel@tonic-gate } 8680Sstevel@tonic-gate 8690Sstevel@tonic-gate /* 8700Sstevel@tonic-gate * Normalize the dependency list if required. 8710Sstevel@tonic-gate */ 8720Sstevel@tonic-gate if (nflag) { 873*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(verdefs, idx1, vdp)) { 874*7682SAli.Bahrami@Sun.COM Aliste idx2; 875*7682SAli.Bahrami@Sun.COM GVer_desc *_vdp; 8760Sstevel@tonic-gate int type = vdp->vd_flags & VER_FLG_WEAK; 8770Sstevel@tonic-gate 878*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) 8790Sstevel@tonic-gate gvers_derefer(_vdp, type); 8800Sstevel@tonic-gate } 8810Sstevel@tonic-gate 8820Sstevel@tonic-gate /* 8830Sstevel@tonic-gate * Always dereference the base version. 8840Sstevel@tonic-gate */ 8850Sstevel@tonic-gate if (bvdp) 8860Sstevel@tonic-gate bvdp->vd_flags &= ~FLG_VER_AVAIL; 8870Sstevel@tonic-gate } 8880Sstevel@tonic-gate 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Traverse the dependency list and print out the appropriate 8920Sstevel@tonic-gate * information. 8930Sstevel@tonic-gate */ 894*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(verdefs, idx1, vdp)) { 895*7682SAli.Bahrami@Sun.COM Aliste idx2; 896*7682SAli.Bahrami@Sun.COM GVer_desc *_vdp; 8970Sstevel@tonic-gate int count; 8980Sstevel@tonic-gate 899*7682SAli.Bahrami@Sun.COM if (!match(NULL, vdp->vd_name, vdp->vd_ndx)) 9000Sstevel@tonic-gate continue; 901*7682SAli.Bahrami@Sun.COM if ((alist_nitems(match_list) == 0) && 902*7682SAli.Bahrami@Sun.COM !(vdp->vd_flags & FLG_VER_AVAIL)) 9030Sstevel@tonic-gate continue; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate error = 1; 9060Sstevel@tonic-gate 9070Sstevel@tonic-gate if (vflag) { 9080Sstevel@tonic-gate /* 9090Sstevel@tonic-gate * If the verbose flag is set determine if this version 9100Sstevel@tonic-gate * has a `weak' attribute, and print any version 9110Sstevel@tonic-gate * dependencies this version inherits. 9120Sstevel@tonic-gate */ 9130Sstevel@tonic-gate if (oflag) 914*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_OFIL), file); 915*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_VER_NAME), vdp->vd_name); 916*7682SAli.Bahrami@Sun.COM if ((vdp->vd_flags & MSK_VER_USER) != 0) { 917*7682SAli.Bahrami@Sun.COM Conv_ver_flags_buf_t ver_flags_buf; 918*7682SAli.Bahrami@Sun.COM 919*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_VER_FLG), 920*7682SAli.Bahrami@Sun.COM conv_ver_flags( 921*7682SAli.Bahrami@Sun.COM vdp->vd_flags & MSK_VER_USER, 922*7682SAli.Bahrami@Sun.COM CONV_FMT_NOBKT, &ver_flags_buf)); 923*7682SAli.Bahrami@Sun.COM } 9240Sstevel@tonic-gate 9250Sstevel@tonic-gate count = 1; 926*7682SAli.Bahrami@Sun.COM for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) { 9270Sstevel@tonic-gate const char *_name = _vdp->vd_name; 9280Sstevel@tonic-gate 9290Sstevel@tonic-gate if (count++ == 1) { 930*7682SAli.Bahrami@Sun.COM 9310Sstevel@tonic-gate if (oflag) 932*7682SAli.Bahrami@Sun.COM (void) printf( 933*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_IN_OFLG), 934*7682SAli.Bahrami@Sun.COM _name); 9350Sstevel@tonic-gate else if (vdp->vd_flags & VER_FLG_WEAK) 936*7682SAli.Bahrami@Sun.COM (void) printf( 937*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_IN_WEAK), 938*7682SAli.Bahrami@Sun.COM _name); 9390Sstevel@tonic-gate else 940*7682SAli.Bahrami@Sun.COM (void) printf( 941*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_IN), 9420Sstevel@tonic-gate _name); 9430Sstevel@tonic-gate } else 944*7682SAli.Bahrami@Sun.COM (void) printf( 945*7682SAli.Bahrami@Sun.COM MSG_ORIG(MSG_FMT_LIST_NEXT), _name); 9460Sstevel@tonic-gate } 9470Sstevel@tonic-gate 9480Sstevel@tonic-gate if (count != 1) 949*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_IN_END)); 9500Sstevel@tonic-gate 951*7682SAli.Bahrami@Sun.COM if (vsdata && !oflag) 952*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_COL_NL)); 9530Sstevel@tonic-gate else 954*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_SEM_NL)); 9550Sstevel@tonic-gate } else { 956*7682SAli.Bahrami@Sun.COM if (vsdata && !oflag) 957*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_TNCO), 958*7682SAli.Bahrami@Sun.COM vdp->vd_name); 959*7682SAli.Bahrami@Sun.COM else if (!vsdata) { 9600Sstevel@tonic-gate if (oflag) 961*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_OFIL), 962*7682SAli.Bahrami@Sun.COM file); 963*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_TNSE), 964*7682SAli.Bahrami@Sun.COM vdp->vd_name); 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate } 9670Sstevel@tonic-gate 968*7682SAli.Bahrami@Sun.COM /* If we are not printing symbols, we're done */ 969*7682SAli.Bahrami@Sun.COM if (vsdata == NULL) 9700Sstevel@tonic-gate continue; 9710Sstevel@tonic-gate 9720Sstevel@tonic-gate /* 973*7682SAli.Bahrami@Sun.COM * If a specific version to match has been specified then 974*7682SAli.Bahrami@Sun.COM * display any of its own symbols plus any inherited from 975*7682SAli.Bahrami@Sun.COM * other versions. Otherwise simply print out the symbols 976*7682SAli.Bahrami@Sun.COM * for this version. 9770Sstevel@tonic-gate */ 978*7682SAli.Bahrami@Sun.COM gvers_syms(vsdata, vdp->vd_ndx, vdp->vd_name, NULL, file); 979*7682SAli.Bahrami@Sun.COM if (alist_nitems(match_list) != 0) { 980*7682SAli.Bahrami@Sun.COM recurse_syms(vsdata, vdp, file); 9810Sstevel@tonic-gate 9820Sstevel@tonic-gate /* 983*7682SAli.Bahrami@Sun.COM * If the verbose flag is set, and this is not 984*7682SAli.Bahrami@Sun.COM * the base version, then add the base version as a 985*7682SAli.Bahrami@Sun.COM * dependency. 9860Sstevel@tonic-gate */ 987*7682SAli.Bahrami@Sun.COM if (vflag && bvdp && 988*7682SAli.Bahrami@Sun.COM !match(NULL, bvdp->vd_name, bvdp->vd_ndx)) { 9890Sstevel@tonic-gate if (!oflag) 990*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_TNCO), 991*7682SAli.Bahrami@Sun.COM bvdp->vd_name); 992*7682SAli.Bahrami@Sun.COM gvers_syms(vsdata, bvdp->vd_ndx, 993*7682SAli.Bahrami@Sun.COM bvdp->vd_name, NULL, file); 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate } 9960Sstevel@tonic-gate } 9970Sstevel@tonic-gate return (error); 9980Sstevel@tonic-gate } 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate int 10010Sstevel@tonic-gate main(int argc, char **argv, char **envp) 10020Sstevel@tonic-gate { 10030Sstevel@tonic-gate GElf_Shdr shdr; 10040Sstevel@tonic-gate Elf *elf; 10050Sstevel@tonic-gate Elf_Scn *scn; 10060Sstevel@tonic-gate Elf_Data *data; 10070Sstevel@tonic-gate GElf_Ehdr ehdr; 10080Sstevel@tonic-gate int nfile, var; 10090Sstevel@tonic-gate char *names; 10100Sstevel@tonic-gate Cache *cache, *_cache; 10110Sstevel@tonic-gate Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc; 10120Sstevel@tonic-gate int error = 0; 1013*7682SAli.Bahrami@Sun.COM Gver_sym_data vsdata_s; 1014*7682SAli.Bahrami@Sun.COM const Gver_sym_data *vsdata = NULL; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate /* 10170Sstevel@tonic-gate * Check for a binary that better fits this architecture. 10180Sstevel@tonic-gate */ 10192647Srie (void) conv_check_native(argv, envp); 10200Sstevel@tonic-gate 10210Sstevel@tonic-gate /* 10220Sstevel@tonic-gate * Establish locale. 10230Sstevel@tonic-gate */ 10240Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 10250Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 10260Sstevel@tonic-gate 10270Sstevel@tonic-gate cname = argv[0]; 10280Sstevel@tonic-gate Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0; 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate opterr = 0; 1031*7682SAli.Bahrami@Sun.COM while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 10320Sstevel@tonic-gate switch (var) { 10330Sstevel@tonic-gate case 'C': 10340Sstevel@tonic-gate Cflag = USR_DEFINED; 10350Sstevel@tonic-gate break; 10360Sstevel@tonic-gate case 'd': 10370Sstevel@tonic-gate dflag = USR_DEFINED; 10380Sstevel@tonic-gate break; 10390Sstevel@tonic-gate case 'l': 1040*7682SAli.Bahrami@Sun.COM lflag = sflag = USR_DEFINED; 10410Sstevel@tonic-gate break; 10420Sstevel@tonic-gate case 'n': 10430Sstevel@tonic-gate nflag = USR_DEFINED; 10440Sstevel@tonic-gate break; 10450Sstevel@tonic-gate case 'o': 10460Sstevel@tonic-gate oflag = USR_DEFINED; 10470Sstevel@tonic-gate break; 10480Sstevel@tonic-gate case 'r': 10490Sstevel@tonic-gate rflag = USR_DEFINED; 10500Sstevel@tonic-gate break; 10510Sstevel@tonic-gate case 's': 10520Sstevel@tonic-gate sflag = USR_DEFINED; 10530Sstevel@tonic-gate break; 10540Sstevel@tonic-gate case 'v': 10550Sstevel@tonic-gate vflag = USR_DEFINED; 10560Sstevel@tonic-gate break; 1057*7682SAli.Bahrami@Sun.COM case 'I': 10580Sstevel@tonic-gate case 'N': 1059*7682SAli.Bahrami@Sun.COM add_match_record(var, optarg); 10600Sstevel@tonic-gate break; 10610Sstevel@tonic-gate case '?': 10620Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 10630Sstevel@tonic-gate cname); 10640Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL)); 10650Sstevel@tonic-gate exit(1); 10660Sstevel@tonic-gate default: 10670Sstevel@tonic-gate break; 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate } 10700Sstevel@tonic-gate 10710Sstevel@tonic-gate /* 10720Sstevel@tonic-gate * No files specified on the command line? 10730Sstevel@tonic-gate */ 10740Sstevel@tonic-gate if ((nfile = argc - optind) == 0) { 10750Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 10760Sstevel@tonic-gate exit(1); 10770Sstevel@tonic-gate } 10780Sstevel@tonic-gate 10790Sstevel@tonic-gate /* 10800Sstevel@tonic-gate * By default print both version definitions and needed dependencies. 10810Sstevel@tonic-gate */ 1082*7682SAli.Bahrami@Sun.COM if ((dflag == 0) && (rflag == 0) && (lflag == 0)) 10830Sstevel@tonic-gate dflag = rflag = DEF_DEFINED; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate /* 10860Sstevel@tonic-gate * Open the input file and initialize the elf interface. 10870Sstevel@tonic-gate */ 10880Sstevel@tonic-gate for (; optind < argc; optind++) { 10890Sstevel@tonic-gate int derror = 0, nerror = 0, err; 10900Sstevel@tonic-gate const char *file = argv[optind]; 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate if ((var = open(file, O_RDONLY)) == -1) { 10930Sstevel@tonic-gate err = errno; 10940Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 10950Sstevel@tonic-gate cname, file, strerror(err)); 10960Sstevel@tonic-gate error = 1; 10970Sstevel@tonic-gate continue; 10980Sstevel@tonic-gate } 10990Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 11000Sstevel@tonic-gate if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) { 11010Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname, 11020Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11030Sstevel@tonic-gate error = 1; 11040Sstevel@tonic-gate (void) close(var); 11050Sstevel@tonic-gate continue; 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate if (elf_kind(elf) != ELF_K_ELF) { 11080Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname, 11090Sstevel@tonic-gate file); 11100Sstevel@tonic-gate error = 1; 11110Sstevel@tonic-gate (void) close(var); 11120Sstevel@tonic-gate (void) elf_end(elf); 11130Sstevel@tonic-gate continue; 11140Sstevel@tonic-gate } 11150Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) { 11160Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname, 11170Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11180Sstevel@tonic-gate error = 1; 11190Sstevel@tonic-gate (void) close(var); 11200Sstevel@tonic-gate (void) elf_end(elf); 11210Sstevel@tonic-gate continue; 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate /* 11250Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required 11260Sstevel@tonic-gate * section name strings. 11270Sstevel@tonic-gate */ 11280Sstevel@tonic-gate if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) { 11290Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname, 11300Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11310Sstevel@tonic-gate error = 1; 11320Sstevel@tonic-gate (void) close(var); 11330Sstevel@tonic-gate (void) elf_end(elf); 11340Sstevel@tonic-gate continue; 11350Sstevel@tonic-gate } 11360Sstevel@tonic-gate if ((data = elf_getdata(scn, NULL)) == NULL) { 11370Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname, 11380Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11390Sstevel@tonic-gate error = 1; 11400Sstevel@tonic-gate (void) close(var); 11410Sstevel@tonic-gate (void) elf_end(elf); 11420Sstevel@tonic-gate continue; 11430Sstevel@tonic-gate } 11440Sstevel@tonic-gate names = data->d_buf; 11450Sstevel@tonic-gate 11460Sstevel@tonic-gate /* 11470Sstevel@tonic-gate * Fill in the cache descriptor with information for each 11480Sstevel@tonic-gate * section we might need. We probably only need to save 11490Sstevel@tonic-gate * read-only allocable sections as this is where the version 11500Sstevel@tonic-gate * structures and their associated symbols and strings live. 11510Sstevel@tonic-gate * However, God knows what someone can do with a mapfile, and 11520Sstevel@tonic-gate * as elf_begin has already gone through all the overhead we 11530Sstevel@tonic-gate * might as well set up the cache for every section. 11540Sstevel@tonic-gate */ 1155*7682SAli.Bahrami@Sun.COM if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == NULL) { 11560Sstevel@tonic-gate int err = errno; 11570Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 11580Sstevel@tonic-gate file, strerror(err)); 11590Sstevel@tonic-gate exit(1); 11600Sstevel@tonic-gate } 11610Sstevel@tonic-gate 1162*7682SAli.Bahrami@Sun.COM _cache_def = _cache_need = _cache_sym = _cache_loc = NULL; 11630Sstevel@tonic-gate _cache = cache; 11640Sstevel@tonic-gate _cache++; 11650Sstevel@tonic-gate for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) { 11660Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL) { 11670Sstevel@tonic-gate (void) fprintf(stderr, 11680Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETSHDR), cname, file, 11690Sstevel@tonic-gate elf_errmsg(elf_errno())); 11700Sstevel@tonic-gate error = 1; 11710Sstevel@tonic-gate continue; 11720Sstevel@tonic-gate } 11730Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == 11740Sstevel@tonic-gate NULL) { 11750Sstevel@tonic-gate (void) fprintf(stderr, 11760Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETDATA), cname, file, 11770Sstevel@tonic-gate elf_errmsg(elf_errno())); 11780Sstevel@tonic-gate error = 1; 11790Sstevel@tonic-gate continue; 11800Sstevel@tonic-gate } 11810Sstevel@tonic-gate _cache->c_scn = scn; 11820Sstevel@tonic-gate _cache->c_name = names + shdr.sh_name; 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate /* 11850Sstevel@tonic-gate * Remember the version sections and symbol table. 11860Sstevel@tonic-gate */ 11872766Sab196087 switch (shdr.sh_type) { 11882766Sab196087 case SHT_SUNW_verdef: 11892766Sab196087 if (dflag) 11902766Sab196087 _cache_def = _cache; 11912766Sab196087 break; 11922766Sab196087 case SHT_SUNW_verneed: 11932766Sab196087 if (rflag) 11942766Sab196087 _cache_need = _cache; 11952766Sab196087 break; 11962766Sab196087 case SHT_SUNW_versym: 11972766Sab196087 if (sflag) 11982766Sab196087 _cache_sym = _cache; 11992766Sab196087 break; 12002766Sab196087 case SHT_SYMTAB: 12012766Sab196087 if (lflag) 12022766Sab196087 _cache_loc = _cache; 12032766Sab196087 break; 12042766Sab196087 } 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate 12070Sstevel@tonic-gate /* 12080Sstevel@tonic-gate * Before printing anything out determine if any warnings are 12090Sstevel@tonic-gate * necessary. 12100Sstevel@tonic-gate */ 1211*7682SAli.Bahrami@Sun.COM if (lflag && (_cache_loc == NULL)) { 12120Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), 12130Sstevel@tonic-gate cname, file); 12140Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB)); 12150Sstevel@tonic-gate } 12160Sstevel@tonic-gate 12170Sstevel@tonic-gate /* 12180Sstevel@tonic-gate * If there is more than one input file, and we're not printing 12190Sstevel@tonic-gate * one-line output, display the filename being processed. 12200Sstevel@tonic-gate */ 12210Sstevel@tonic-gate if ((nfile > 1) && !oflag) 1222*7682SAli.Bahrami@Sun.COM (void) printf(MSG_ORIG(MSG_FMT_FILE), file); 1223*7682SAli.Bahrami@Sun.COM 1224*7682SAli.Bahrami@Sun.COM /* 1225*7682SAli.Bahrami@Sun.COM * If we're printing symbols, then collect the data 1226*7682SAli.Bahrami@Sun.COM * necessary to do that. 1227*7682SAli.Bahrami@Sun.COM */ 1228*7682SAli.Bahrami@Sun.COM if (_cache_sym != NULL) { 1229*7682SAli.Bahrami@Sun.COM vsdata = &vsdata_s; 1230*7682SAli.Bahrami@Sun.COM (void) gelf_getshdr(_cache_sym->c_scn, &shdr); 1231*7682SAli.Bahrami@Sun.COM vsdata_s.vsd_vsp = 1232*7682SAli.Bahrami@Sun.COM (GElf_Versym *)_cache_sym->c_data->d_buf; 1233*7682SAli.Bahrami@Sun.COM vsdata_s.vsd_sym_data = cache[shdr.sh_link].c_data; 1234*7682SAli.Bahrami@Sun.COM (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr); 1235*7682SAli.Bahrami@Sun.COM vsdata_s.vsd_symn = shdr.sh_size / shdr.sh_entsize; 1236*7682SAli.Bahrami@Sun.COM vsdata_s.vsd_strs = 1237*7682SAli.Bahrami@Sun.COM (const char *)cache[shdr.sh_link].c_data->d_buf; 1238*7682SAli.Bahrami@Sun.COM } 1239*7682SAli.Bahrami@Sun.COM 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate /* 12420Sstevel@tonic-gate * Print the files version needed sections. 12430Sstevel@tonic-gate */ 12440Sstevel@tonic-gate if (_cache_need) 1245*7682SAli.Bahrami@Sun.COM nerror = gvers_need(cache, _cache_need, vsdata, file); 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate /* 12480Sstevel@tonic-gate * Print the files version definition sections. 12490Sstevel@tonic-gate */ 12500Sstevel@tonic-gate if (_cache_def) 1251*7682SAli.Bahrami@Sun.COM derror = gvers_def(cache, _cache_def, vsdata, file); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate /* 12540Sstevel@tonic-gate * Print any local symbol reductions. 12550Sstevel@tonic-gate */ 12560Sstevel@tonic-gate if (_cache_loc) 12570Sstevel@tonic-gate sym_local(cache, _cache_loc, file); 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate /* 12600Sstevel@tonic-gate * Determine the error return. There are three conditions that 12610Sstevel@tonic-gate * may produce an error (a non-zero return): 12620Sstevel@tonic-gate * 12630Sstevel@tonic-gate * o if the user specified -d and no version definitions 12640Sstevel@tonic-gate * were found. 12650Sstevel@tonic-gate * 12660Sstevel@tonic-gate * o if the user specified -r and no version requirements 12670Sstevel@tonic-gate * were found. 12680Sstevel@tonic-gate * 12690Sstevel@tonic-gate * o if the user specified neither -d or -r, (thus both are 12700Sstevel@tonic-gate * enabled by default), and no version definitions or 12710Sstevel@tonic-gate * version dependencies were found. 12720Sstevel@tonic-gate */ 12730Sstevel@tonic-gate if (((dflag == USR_DEFINED) && (derror == 0)) || 12740Sstevel@tonic-gate ((rflag == USR_DEFINED) && (nerror == 0)) || 12750Sstevel@tonic-gate (rflag && dflag && (derror == 0) && (nerror == 0))) 12760Sstevel@tonic-gate error = 1; 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate (void) close(var); 12790Sstevel@tonic-gate (void) elf_end(elf); 12800Sstevel@tonic-gate free(cache); 12810Sstevel@tonic-gate } 12820Sstevel@tonic-gate return (error); 12830Sstevel@tonic-gate } 12840Sstevel@tonic-gate 12850Sstevel@tonic-gate const char * 12860Sstevel@tonic-gate _pvs_msg(Msg mid) 12870Sstevel@tonic-gate { 12880Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 12890Sstevel@tonic-gate } 1290