17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 215aefb655Srie 227c478bd9Sstevel@tonic-gate /* 23*d444b03eSAli Bahrami * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Analyze the versioning information within a file. 297c478bd9Sstevel@tonic-gate * 307c478bd9Sstevel@tonic-gate * -C demangle C++ symbol names. 317c478bd9Sstevel@tonic-gate * 327c478bd9Sstevel@tonic-gate * -d dump version definitions. 337c478bd9Sstevel@tonic-gate * 34090a8d9eSAli Bahrami * -l print reduced (local) symbols. Implies -s. 357c478bd9Sstevel@tonic-gate * 367c478bd9Sstevel@tonic-gate * -n normalize any version definitions. 377c478bd9Sstevel@tonic-gate * 387c478bd9Sstevel@tonic-gate * -o dump output in one-line fashion (more suitable for grep'ing 397c478bd9Sstevel@tonic-gate * and diff'ing). 407c478bd9Sstevel@tonic-gate * 417c478bd9Sstevel@tonic-gate * -r dump the version requirements on library dependencies 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * -s display the symbols associated with each version definition. 447c478bd9Sstevel@tonic-gate * 457c478bd9Sstevel@tonic-gate * -v verbose output. With the -r and -d options any WEAK attribute 467c478bd9Sstevel@tonic-gate * is displayed. With the -d option, any version inheritance, 47090a8d9eSAli Bahrami * and the base version are displayed. With the -r option, 48090a8d9eSAli Bahrami * WEAK and INFO attributes are displayed. With the -s option 49090a8d9eSAli Bahrami * the version symbol is displayed. 50090a8d9eSAli Bahrami * 51090a8d9eSAli Bahrami * -I index only print the specifed version index, or index range. 527c478bd9Sstevel@tonic-gate * 537c478bd9Sstevel@tonic-gate * -N name only print the specifed `name'. 547c478bd9Sstevel@tonic-gate */ 557c478bd9Sstevel@tonic-gate #include <fcntl.h> 567c478bd9Sstevel@tonic-gate #include <stdio.h> 577c478bd9Sstevel@tonic-gate #include <libelf.h> 587c478bd9Sstevel@tonic-gate #include <link.h> 597c478bd9Sstevel@tonic-gate #include <stdlib.h> 607c478bd9Sstevel@tonic-gate #include <string.h> 617c478bd9Sstevel@tonic-gate #include <unistd.h> 627c478bd9Sstevel@tonic-gate #include <locale.h> 637c478bd9Sstevel@tonic-gate #include <errno.h> 645aefb655Srie #include <sgs.h> 655aefb655Srie #include <conv.h> 665aefb655Srie #include <gelf.h> 675aefb655Srie #include <debug.h> 68090a8d9eSAli Bahrami #include <ctype.h> 69090a8d9eSAli Bahrami #include <alist.h> 707c478bd9Sstevel@tonic-gate #include "msg.h" 717c478bd9Sstevel@tonic-gate 72090a8d9eSAli Bahrami /* 73090a8d9eSAli Bahrami * Define Alist initialization sizes. 74090a8d9eSAli Bahrami */ 75090a8d9eSAli Bahrami #define AL_CNT_MATCH_LIST 5 /* match_list initial alist count */ 76090a8d9eSAli Bahrami #define AL_CNT_GVER_DESC 25 /* version tracking descriptors */ 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate typedef struct cache { 797c478bd9Sstevel@tonic-gate Elf_Scn *c_scn; 807c478bd9Sstevel@tonic-gate Elf_Data *c_data; 817c478bd9Sstevel@tonic-gate char *c_name; 827c478bd9Sstevel@tonic-gate } Cache; 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate typedef struct gver_desc { 857c478bd9Sstevel@tonic-gate const char *vd_name; 867c478bd9Sstevel@tonic-gate unsigned long vd_hash; 877c478bd9Sstevel@tonic-gate GElf_Half vd_ndx; 887c478bd9Sstevel@tonic-gate GElf_Half vd_flags; 89090a8d9eSAli Bahrami APlist *vd_deps; 907c478bd9Sstevel@tonic-gate } GVer_desc; 917c478bd9Sstevel@tonic-gate 92090a8d9eSAli Bahrami /* Versym related data used by gvers_syms() */ 93090a8d9eSAli Bahrami typedef struct { 94090a8d9eSAli Bahrami GElf_Versym *vsd_vsp; /* ptr to versym data */ 95090a8d9eSAli Bahrami Elf_Data *vsd_sym_data; /* ptr to symtab data */ 96090a8d9eSAli Bahrami Word vsd_symn; /* # of symbols in symtab */ 97090a8d9eSAli Bahrami const char *vsd_strs; /* string table data */ 98090a8d9eSAli Bahrami } Gver_sym_data; 99090a8d9eSAli Bahrami 100090a8d9eSAli Bahrami /* 101090a8d9eSAli Bahrami * Type used to manage -I and -N options: 102090a8d9eSAli Bahrami * 103090a8d9eSAli Bahrami * The -I option specifies a VERSYM index, or index range. The 104090a8d9eSAli Bahrami * result is to select the VERDEF or VERNEED records with 105090a8d9eSAli Bahrami * indexes that match those given. 106090a8d9eSAli Bahrami * 107090a8d9eSAli Bahrami * -N options come in two forms: 108090a8d9eSAli Bahrami * 109090a8d9eSAli Bahrami * 1) name 110090a8d9eSAli Bahrami * 2) needobj (version) 111090a8d9eSAli Bahrami * 112090a8d9eSAli Bahrami * The meaning of the first case depends on the type of 113090a8d9eSAli Bahrami * version record being matched: 114090a8d9eSAli Bahrami * 115090a8d9eSAli Bahrami * VERDEF - name is the name of a version defined 116090a8d9eSAli Bahrami * by the object being processed (i.e. SUNW_1.1). 117090a8d9eSAli Bahrami * 118090a8d9eSAli Bahrami * VERNEED - name is the name of the object file 119090a8d9eSAli Bahrami * on which the dependency exists (i.e. libc.so.1). 120090a8d9eSAli Bahrami * 121090a8d9eSAli Bahrami * -N options of the second form only apply to VERNEED records. 122090a8d9eSAli Bahrami * They are used to specify a version from a needed object. 123090a8d9eSAli Bahrami */ 124090a8d9eSAli Bahrami /* match_opt_t is used to note which match option was used */ 125090a8d9eSAli Bahrami typedef enum { 126090a8d9eSAli Bahrami MATCH_OPT_NAME, /* Record contains a name */ 127090a8d9eSAli Bahrami MATCH_OPT_NEED_VER, /* Record contains needed object and version */ 128090a8d9eSAli Bahrami MATCH_OPT_NDX, /* Record contains a single index */ 129090a8d9eSAli Bahrami MATCH_OPT_RANGE, /* Record contains an index range */ 130090a8d9eSAli Bahrami } match_opt_t; 131090a8d9eSAli Bahrami 132090a8d9eSAli Bahrami typedef struct { 133090a8d9eSAli Bahrami match_opt_t opt_type; 134090a8d9eSAli Bahrami union { 135090a8d9eSAli Bahrami struct { 136090a8d9eSAli Bahrami const char *version; /* MATCH_OPT_{NAME|NEED_VER} */ 137090a8d9eSAli Bahrami const char *needobj; /* MATCH_OPT_NEED_VER only */ 138090a8d9eSAli Bahrami } name; 139090a8d9eSAli Bahrami struct { 140090a8d9eSAli Bahrami int start; /* MATCH_OPT_{NDX|RANGE} */ 141090a8d9eSAli Bahrami int end; /* MATCH_OPT_RANGE only) */ 142090a8d9eSAli Bahrami } ndx; 143090a8d9eSAli Bahrami } value; 144090a8d9eSAli Bahrami } match_rec_t; 145090a8d9eSAli Bahrami 146090a8d9eSAli Bahrami 147090a8d9eSAli Bahrami 1487c478bd9Sstevel@tonic-gate static const char *cname; 1497c478bd9Sstevel@tonic-gate static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag; 150090a8d9eSAli Bahrami static Alist *match_list; 1517c478bd9Sstevel@tonic-gate 152090a8d9eSAli Bahrami /* Used to track whether an option defaulted to on, or was explicitly set */ 1537c478bd9Sstevel@tonic-gate #define DEF_DEFINED 1 1547c478bd9Sstevel@tonic-gate #define USR_DEFINED 2 1557c478bd9Sstevel@tonic-gate 1567c478bd9Sstevel@tonic-gate /* 1577c478bd9Sstevel@tonic-gate * Determine whether a symbol name should be demangled. 1587c478bd9Sstevel@tonic-gate */ 1597c478bd9Sstevel@tonic-gate static const char * 1607c478bd9Sstevel@tonic-gate demangle(const char *name) 1617c478bd9Sstevel@tonic-gate { 1627c478bd9Sstevel@tonic-gate if (Cflag) 1635aefb655Srie return (Elf_demangle_name(name)); 1647c478bd9Sstevel@tonic-gate else 1657c478bd9Sstevel@tonic-gate return (name); 1667c478bd9Sstevel@tonic-gate } 1677c478bd9Sstevel@tonic-gate 168090a8d9eSAli Bahrami /* 169090a8d9eSAli Bahrami * Append an item to the specified list, and return a pointer to the list 170090a8d9eSAli Bahrami * node created. 171090a8d9eSAli Bahrami * 172090a8d9eSAli Bahrami * exit: 173090a8d9eSAli Bahrami * On success, a new list node is created and the item is 174090a8d9eSAli Bahrami * added to the list. On failure, a fatal error is issued 175090a8d9eSAli Bahrami * and the process exits. 176090a8d9eSAli Bahrami */ 177090a8d9eSAli Bahrami static void 178090a8d9eSAli Bahrami pvs_aplist_append(APlist **lst, const void *item, const char *file) 179090a8d9eSAli Bahrami { 180090a8d9eSAli Bahrami if (aplist_append(lst, item, AL_CNT_GVER_DESC) == NULL) { 181090a8d9eSAli Bahrami int err = errno; 182090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file, 183090a8d9eSAli Bahrami strerror(err)); 184090a8d9eSAli Bahrami exit(1); 185090a8d9eSAli Bahrami } 186090a8d9eSAli Bahrami } 187090a8d9eSAli Bahrami 188090a8d9eSAli Bahrami /* 189090a8d9eSAli Bahrami * Add an entry to match_list for use by match(). This routine is for 190090a8d9eSAli Bahrami * use during getopt() processing. 191090a8d9eSAli Bahrami * 192090a8d9eSAli Bahrami * entry: 193090a8d9eSAli Bahrami * opt - One of 'N' or 'I', indicating the option 194090a8d9eSAli Bahrami * str - Value string corresponding to opt 195090a8d9eSAli Bahrami * 196090a8d9eSAli Bahrami * exit: 197090a8d9eSAli Bahrami * The new match record has been added. On error, a fatal 198090a8d9eSAli Bahrami * error is issued and and the process exits. 199090a8d9eSAli Bahrami */ 200090a8d9eSAli Bahrami static void 201090a8d9eSAli Bahrami add_match_record(int opt, const char *str) 202090a8d9eSAli Bahrami { 203090a8d9eSAli Bahrami /* 204090a8d9eSAli Bahrami * Macros for removing leading and trailing whitespace: 205090a8d9eSAli Bahrami * WS_SKIP - Advance _str without passing the NULL termination, 206090a8d9eSAli Bahrami * until the first character is not whitespace. 207090a8d9eSAli Bahrami * WS_SKIP_LIMIT - Advance _str without passing _limit, 208090a8d9eSAli Bahrami * until the first character is not whitespace. 209090a8d9eSAli Bahrami * WS_RSKIP_LIMIT - Move _tail back without passing _str, 210090a8d9eSAli Bahrami * until the character before it is not whitespace. 211090a8d9eSAli Bahrami * Write a NULL termination at that point. 212090a8d9eSAli Bahrami */ 213090a8d9eSAli Bahrami #define WS_SKIP(_str) for (; *(_str) && isspace(*(_str)); (_str)++) 214090a8d9eSAli Bahrami #define WS_SKIP_LIMIT(_str, _limit) \ 215090a8d9eSAli Bahrami while (((_str) < s2) && isspace(*(_str))) \ 216090a8d9eSAli Bahrami (_str)++ 217090a8d9eSAli Bahrami #define WS_RSKIP_LIMIT(_str, _tail) \ 218090a8d9eSAli Bahrami while (((_tail) > (_str)) && isspace(*((_tail) - 1))) \ 219090a8d9eSAli Bahrami (_tail)--; \ 220090a8d9eSAli Bahrami *(_tail) = '\0' 221090a8d9eSAli Bahrami 222090a8d9eSAli Bahrami 223090a8d9eSAli Bahrami match_rec_t *rec; 224090a8d9eSAli Bahrami char *lstr, *s1, *s2; 225090a8d9eSAli Bahrami 226090a8d9eSAli Bahrami rec = alist_append(&match_list, NULL, sizeof (match_rec_t), 227090a8d9eSAli Bahrami AL_CNT_MATCH_LIST); 228090a8d9eSAli Bahrami if (rec == NULL) { 229090a8d9eSAli Bahrami int err = errno; 230090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 231090a8d9eSAli Bahrami MSG_INTL(MSG_STR_MATCH_RECORD), strerror(err)); 232090a8d9eSAli Bahrami exit(1); 233090a8d9eSAli Bahrami } 234090a8d9eSAli Bahrami 235090a8d9eSAli Bahrami if (opt == 'N') { 236090a8d9eSAli Bahrami if ((lstr = strdup(str)) == NULL) { 237090a8d9eSAli Bahrami int err = errno; 238090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 239090a8d9eSAli Bahrami cname, MSG_INTL(MSG_STR_MATCH_RECORD), 240090a8d9eSAli Bahrami strerror(err)); 241090a8d9eSAli Bahrami exit(1); 242090a8d9eSAli Bahrami } 243090a8d9eSAli Bahrami 244090a8d9eSAli Bahrami /* Strip leading/trailing whitespace */ 245090a8d9eSAli Bahrami s2 = lstr + strlen(lstr); 246090a8d9eSAli Bahrami WS_SKIP_LIMIT(lstr, s2); 247090a8d9eSAli Bahrami WS_RSKIP_LIMIT(lstr, s2); 248090a8d9eSAli Bahrami 249090a8d9eSAli Bahrami /* Assume this is a plain string */ 250090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_NAME; 251090a8d9eSAli Bahrami rec->value.name.version = lstr; 252090a8d9eSAli Bahrami 253090a8d9eSAli Bahrami /* 254090a8d9eSAli Bahrami * If s2 points at a closing paren, then this might 255090a8d9eSAli Bahrami * be a MATCH_OPT_NEED_VER case. Otherwise we're done. 256090a8d9eSAli Bahrami */ 257090a8d9eSAli Bahrami if ((s2 == lstr) || (*(s2 - 1) != ')')) 258090a8d9eSAli Bahrami return; 259090a8d9eSAli Bahrami 260090a8d9eSAli Bahrami /* We have a closing paren. Locate the opening one. */ 261090a8d9eSAli Bahrami for (s1 = lstr; *s1 && (*s1 != '('); s1++) 262090a8d9eSAli Bahrami ; 263090a8d9eSAli Bahrami if (*s1 != '(') 264090a8d9eSAli Bahrami return; 265090a8d9eSAli Bahrami 266090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_NEED_VER; 267090a8d9eSAli Bahrami rec->value.name.needobj = lstr; 268090a8d9eSAli Bahrami rec->value.name.version = s1 + 1; 269090a8d9eSAli Bahrami s2--; /* Points at closing paren */ 270090a8d9eSAli Bahrami 271090a8d9eSAli Bahrami /* Remove whitespace from head/tail of version */ 272090a8d9eSAli Bahrami WS_SKIP_LIMIT(rec->value.name.version, s2); 273090a8d9eSAli Bahrami WS_RSKIP_LIMIT(rec->value.name.version, s2); 274090a8d9eSAli Bahrami 275090a8d9eSAli Bahrami /* Terminate needobj, skipping trailing whitespace */ 276090a8d9eSAli Bahrami WS_RSKIP_LIMIT(rec->value.name.needobj, s1); 277090a8d9eSAli Bahrami 278090a8d9eSAli Bahrami return; 279090a8d9eSAli Bahrami } 280090a8d9eSAli Bahrami 281090a8d9eSAli Bahrami 282090a8d9eSAli Bahrami /* If we get here, we are looking at a -I index option */ 283090a8d9eSAli Bahrami rec->value.ndx.start = strtol(str, &s2, 10); 284090a8d9eSAli Bahrami /* Value must use some of the input, and be positive */ 285090a8d9eSAli Bahrami if ((str == s2) || (rec->value.ndx.start < 1)) 286090a8d9eSAli Bahrami goto syntax_error; 287090a8d9eSAli Bahrami str = s2; 288090a8d9eSAli Bahrami 289090a8d9eSAli Bahrami WS_SKIP(str); 290090a8d9eSAli Bahrami if (*str != ':') { 291090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_NDX; 292090a8d9eSAli Bahrami } else { 293090a8d9eSAli Bahrami str++; /* Skip the ':' */ 294090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_RANGE; 295090a8d9eSAli Bahrami WS_SKIP(str); 296090a8d9eSAli Bahrami if (*str == '\0') { 297090a8d9eSAli Bahrami rec->value.ndx.end = -1; /* Indicates "to end" */ 298090a8d9eSAli Bahrami } else { 299090a8d9eSAli Bahrami rec->value.ndx.end = strtol(str, &s2, 10); 300090a8d9eSAli Bahrami if ((str == s2) || (rec->value.ndx.end < 0)) 301090a8d9eSAli Bahrami goto syntax_error; 302090a8d9eSAli Bahrami str = s2; 303090a8d9eSAli Bahrami WS_SKIP(str); 304090a8d9eSAli Bahrami } 305090a8d9eSAli Bahrami } 306090a8d9eSAli Bahrami 307090a8d9eSAli Bahrami /* If we are successful, there is nothing left to parse */ 308090a8d9eSAli Bahrami if (*str == '\0') 309090a8d9eSAli Bahrami return; 310090a8d9eSAli Bahrami 311090a8d9eSAli Bahrami /* 312090a8d9eSAli Bahrami * If we get here, there is leftover input. Fall through 313090a8d9eSAli Bahrami * to issue a syntax error. 314090a8d9eSAli Bahrami */ 315090a8d9eSAli Bahrami syntax_error: 316090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 317090a8d9eSAli Bahrami exit(1); 318090a8d9eSAli Bahrami 319090a8d9eSAli Bahrami #undef WS_SKIP 320090a8d9eSAli Bahrami #undef WS_SKIP_LIMIT 321090a8d9eSAli Bahrami #undef WS_RSKIP_LIMIT 322090a8d9eSAli Bahrami } 323090a8d9eSAli Bahrami 324090a8d9eSAli Bahrami /* 325090a8d9eSAli Bahrami * Returns True (1) if the version with the given name or index should 326090a8d9eSAli Bahrami * be displayed, and False (0) if it should not be. 327090a8d9eSAli Bahrami * 328090a8d9eSAli Bahrami * entry: 329090a8d9eSAli Bahrami * needobj - NULL for VERDEF records, the name of the 330090a8d9eSAli Bahrami * needed object for VERNEED. 331090a8d9eSAli Bahrami * version - NULL, or needed version 332090a8d9eSAli Bahrami * ndx - Versym index of version under consideration, or a value less 333090a8d9eSAli Bahrami * than 1 to indicate that no valid index is given. 334090a8d9eSAli Bahrami * 335090a8d9eSAli Bahrami * exit: 336090a8d9eSAli Bahrami * True will be returned if the given name/index matches those given 337090a8d9eSAli Bahrami * by one of the -I or -N command line options, or if no such option 338090a8d9eSAli Bahrami * was used in the command invocation. 339090a8d9eSAli Bahrami */ 340090a8d9eSAli Bahrami int 341090a8d9eSAli Bahrami match(const char *needobj, const char *version, int ndx) 342090a8d9eSAli Bahrami { 343090a8d9eSAli Bahrami Aliste _idx; 344090a8d9eSAli Bahrami match_rec_t *rec; 345090a8d9eSAli Bahrami const char *str; 346090a8d9eSAli Bahrami 347090a8d9eSAli Bahrami /* If there is no match list, then we approve everything */ 348090a8d9eSAli Bahrami if (alist_nitems(match_list) == 0) 349090a8d9eSAli Bahrami return (1); 350090a8d9eSAli Bahrami 351090a8d9eSAli Bahrami /* Run through the match records and check for a hit */ 352090a8d9eSAli Bahrami for (ALIST_TRAVERSE(match_list, _idx, rec)) { 353090a8d9eSAli Bahrami switch (rec->opt_type) { 354090a8d9eSAli Bahrami case MATCH_OPT_NAME: 355090a8d9eSAli Bahrami if (needobj) 356090a8d9eSAli Bahrami str = needobj; 357090a8d9eSAli Bahrami else if (version) 358090a8d9eSAli Bahrami str = version; 359090a8d9eSAli Bahrami else 360090a8d9eSAli Bahrami break; 361090a8d9eSAli Bahrami if (strcmp(rec->value.name.version, str) == 0) 362090a8d9eSAli Bahrami return (1); 363090a8d9eSAli Bahrami break; 364090a8d9eSAli Bahrami case MATCH_OPT_NEED_VER: 365090a8d9eSAli Bahrami if (needobj && version && 366090a8d9eSAli Bahrami (strcmp(rec->value.name.needobj, needobj) == 0) && 367090a8d9eSAli Bahrami (strcmp(rec->value.name.version, version) == 0)) 368090a8d9eSAli Bahrami return (1); 369090a8d9eSAli Bahrami break; 370090a8d9eSAli Bahrami case MATCH_OPT_NDX: 371090a8d9eSAli Bahrami if ((ndx > 0) && (ndx == rec->value.ndx.start)) 372090a8d9eSAli Bahrami return (1); 373090a8d9eSAli Bahrami break; 374090a8d9eSAli Bahrami case MATCH_OPT_RANGE: 375090a8d9eSAli Bahrami /* 376090a8d9eSAli Bahrami * A range end value less than 0 means that any value 377090a8d9eSAli Bahrami * above the start is acceptible. 378090a8d9eSAli Bahrami */ 379090a8d9eSAli Bahrami if ((ndx > 0) && 380090a8d9eSAli Bahrami (ndx >= rec->value.ndx.start) && 381090a8d9eSAli Bahrami ((rec->value.ndx.end < 0) || 382090a8d9eSAli Bahrami (ndx <= rec->value.ndx.end))) 383090a8d9eSAli Bahrami return (1); 384090a8d9eSAli Bahrami break; 385090a8d9eSAli Bahrami } 386090a8d9eSAli Bahrami } 387090a8d9eSAli Bahrami 388090a8d9eSAli Bahrami /* Nothing matched */ 389090a8d9eSAli Bahrami return (0); 390090a8d9eSAli Bahrami } 391090a8d9eSAli Bahrami 392090a8d9eSAli Bahrami /* 393090a8d9eSAli Bahrami * List the symbols that belong to a specified version 394090a8d9eSAli Bahrami * 395090a8d9eSAli Bahrami * entry: 396090a8d9eSAli Bahrami * vsdata - VERSYM related data from the object 397090a8d9eSAli Bahrami * vd_ndx - The VERSYM index for symbols to display 398090a8d9eSAli Bahrami * vd_name - Version name 399090a8d9eSAli Bahrami * needobj - NULL for symbols corresponding to a VERDEF 400090a8d9eSAli Bahrami * record. Name of the needed object in the case 401090a8d9eSAli Bahrami * of a VERNEED record. 402090a8d9eSAli Bahrami * file - Object file 403090a8d9eSAli Bahrami */ 404090a8d9eSAli Bahrami static void 405090a8d9eSAli Bahrami gvers_syms(const Gver_sym_data *vsdata, GElf_Half vd_ndx, 406090a8d9eSAli Bahrami const char *vd_name, const char *needobj, const char *file) 407090a8d9eSAli Bahrami { 408090a8d9eSAli Bahrami GElf_Sym sym; 409090a8d9eSAli Bahrami int _symn; 410090a8d9eSAli Bahrami 411090a8d9eSAli Bahrami for (_symn = 0; _symn < vsdata->vsd_symn; _symn++) { 412090a8d9eSAli Bahrami size_t size = 0; 413090a8d9eSAli Bahrami const char *name; 414090a8d9eSAli Bahrami 415090a8d9eSAli Bahrami if (vsdata->vsd_vsp[_symn] != vd_ndx) 416090a8d9eSAli Bahrami continue; 417090a8d9eSAli Bahrami 418090a8d9eSAli Bahrami (void) gelf_getsym(vsdata->vsd_sym_data, _symn, &sym); 419090a8d9eSAli Bahrami name = demangle(vsdata->vsd_strs + sym.st_name); 420090a8d9eSAli Bahrami 421090a8d9eSAli Bahrami /* 422090a8d9eSAli Bahrami * Symbols that reference a VERDEF record 423090a8d9eSAli Bahrami * have some extra details to handle. 424090a8d9eSAli Bahrami */ 425090a8d9eSAli Bahrami if (needobj == NULL) { 426090a8d9eSAli Bahrami /* 427090a8d9eSAli Bahrami * For data symbols defined by this object, 428090a8d9eSAli Bahrami * determine the size. 429090a8d9eSAli Bahrami */ 430090a8d9eSAli Bahrami if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) || 431090a8d9eSAli Bahrami (GELF_ST_TYPE(sym.st_info) == STT_COMMON) || 432090a8d9eSAli Bahrami (GELF_ST_TYPE(sym.st_info) == STT_TLS)) 433090a8d9eSAli Bahrami size = (size_t)sym.st_size; 434090a8d9eSAli Bahrami 435090a8d9eSAli Bahrami /* 436090a8d9eSAli Bahrami * Only output the version symbol when the verbose 437090a8d9eSAli Bahrami * flag is used. 438090a8d9eSAli Bahrami */ 439090a8d9eSAli Bahrami if (!vflag && (sym.st_shndx == SHN_ABS) && 440090a8d9eSAli Bahrami (strcmp(name, vd_name) == 0)) 441090a8d9eSAli Bahrami continue; 442090a8d9eSAli Bahrami } 443090a8d9eSAli Bahrami 444090a8d9eSAli Bahrami if (oflag) { 445090a8d9eSAli Bahrami if (needobj == NULL) 446090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_OFIL), 447090a8d9eSAli Bahrami file, vd_name); 448090a8d9eSAli Bahrami else 449090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_NEED_OFIL), 450090a8d9eSAli Bahrami file, needobj, vd_name); 451090a8d9eSAli Bahrami 452090a8d9eSAli Bahrami if (size) 453090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ_OFLG), 454090a8d9eSAli Bahrami name, (ulong_t)size); 455090a8d9eSAli Bahrami else 456090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_OFLG), name); 457090a8d9eSAli Bahrami } else { 458090a8d9eSAli Bahrami if (size) 459090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ), name, 460090a8d9eSAli Bahrami (ulong_t)size); 461090a8d9eSAli Bahrami else 462090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM), name); 463090a8d9eSAli Bahrami } 464090a8d9eSAli Bahrami } 465090a8d9eSAli Bahrami } 466090a8d9eSAli Bahrami 4677c478bd9Sstevel@tonic-gate /* 4687c478bd9Sstevel@tonic-gate * Print any reduced symbols. The convention is that reduced symbols exist as 4697c478bd9Sstevel@tonic-gate * LOCL entries in the .symtab, between the FILE symbol for the output file and 4707c478bd9Sstevel@tonic-gate * the first FILE symbol for any input file used to build the output file. 4717c478bd9Sstevel@tonic-gate */ 4727c478bd9Sstevel@tonic-gate static void 4737c478bd9Sstevel@tonic-gate sym_local(Cache *cache, Cache *csym, const char *file) 4747c478bd9Sstevel@tonic-gate { 4757c478bd9Sstevel@tonic-gate int symn, _symn, found = 0; 4767c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 4777c478bd9Sstevel@tonic-gate GElf_Sym sym; 478090a8d9eSAli Bahrami char *strs; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate (void) gelf_getshdr(csym->c_scn, &shdr); 4817c478bd9Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 4827c478bd9Sstevel@tonic-gate /* LINTED */ 4837c478bd9Sstevel@tonic-gate symn = shdr.sh_info; 4847c478bd9Sstevel@tonic-gate 4857c478bd9Sstevel@tonic-gate /* 4867c478bd9Sstevel@tonic-gate * Verify symtab[1] is the output file symbol. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, 1, &sym); 4897c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_FILE) { 4907c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname, 4917c478bd9Sstevel@tonic-gate file); 4927c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE), 4937c478bd9Sstevel@tonic-gate csym->c_name); 4947c478bd9Sstevel@tonic-gate return; 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate /* 4987c478bd9Sstevel@tonic-gate * Scan the remaining symbols until the next file symbol is found. 4997c478bd9Sstevel@tonic-gate */ 5007c478bd9Sstevel@tonic-gate for (_symn = 2; _symn < symn; _symn++) { 5017c478bd9Sstevel@tonic-gate const char *name; 5027c478bd9Sstevel@tonic-gate 5037c478bd9Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, _symn, &sym); 5047c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) 5057c478bd9Sstevel@tonic-gate continue; 5067c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 5077c478bd9Sstevel@tonic-gate break; 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * Its possible that section symbols are followed immediately 5117c478bd9Sstevel@tonic-gate * by globals. This is the case if an object (filter) is 5127c478bd9Sstevel@tonic-gate * generated exclusively from mapfile symbol definitions. 5137c478bd9Sstevel@tonic-gate */ 5147c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym.st_info) != STB_LOCAL) 5157c478bd9Sstevel@tonic-gate break; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate name = demangle(strs + sym.st_name); 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate if (oflag) { 520090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_OFLG), 521090a8d9eSAli Bahrami file, name); 5227c478bd9Sstevel@tonic-gate } else { 5237c478bd9Sstevel@tonic-gate if (found == 0) { 5247c478bd9Sstevel@tonic-gate found = 1; 525090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_HDR)); 5267c478bd9Sstevel@tonic-gate } 527090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LOCSYM), name); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate /* 533090a8d9eSAli Bahrami * Print data from the files VERNEED section. 534090a8d9eSAli Bahrami * 535090a8d9eSAli Bahrami * If we have been asked to display symbols, then the 536090a8d9eSAli Bahrami * output format follows that used for verdef sections, 537090a8d9eSAli Bahrami * with each version displayed separately. For instance: 538090a8d9eSAli Bahrami * 539090a8d9eSAli Bahrami * libc.so.1 (SUNW_1.7): 540090a8d9eSAli Bahrami * sym1; 541090a8d9eSAli Bahrami * sym2; 542090a8d9eSAli Bahrami * libc.so.1 (SUNW_1.9): 543090a8d9eSAli Bahrami * sym3; 544090a8d9eSAli Bahrami * 545090a8d9eSAli Bahrami * If we are not displaying symbols, then a terse format 546090a8d9eSAli Bahrami * is used, which combines all the needed versions from 547090a8d9eSAli Bahrami * a given object into a single line. In this case, the 548090a8d9eSAli Bahrami * versions are shown whether or not they contribute symbols. 549090a8d9eSAli Bahrami * 550090a8d9eSAli Bahrami * libc.so.1 (SUNW_1.7, SUNW_1.9); 5517c478bd9Sstevel@tonic-gate */ 5527c478bd9Sstevel@tonic-gate static int 553090a8d9eSAli Bahrami gvers_need(Cache *cache, Cache *need, const Gver_sym_data *vsdata, 554090a8d9eSAli Bahrami const char *file) 5557c478bd9Sstevel@tonic-gate { 5567c478bd9Sstevel@tonic-gate unsigned int num, _num; 5577c478bd9Sstevel@tonic-gate char *strs; 5587c478bd9Sstevel@tonic-gate GElf_Verneed *vnd = need->c_data->d_buf; 5597c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 5607c478bd9Sstevel@tonic-gate int error = 0; 561090a8d9eSAli Bahrami int show = vflag || (vsdata == NULL) || !oflag; 562090a8d9eSAli Bahrami 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate (void) gelf_getshdr(need->c_scn, &shdr); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * Verify the version revision. We only check the first version 5687c478bd9Sstevel@tonic-gate * structure as it is assumed all other version structures in this 5697c478bd9Sstevel@tonic-gate * data section will be of the same revision. 5707c478bd9Sstevel@tonic-gate */ 5717c478bd9Sstevel@tonic-gate if (vnd->vn_version > VER_DEF_CURRENT) 5727c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 5737c478bd9Sstevel@tonic-gate vnd->vn_version, VER_DEF_CURRENT); 5747c478bd9Sstevel@tonic-gate 5757c478bd9Sstevel@tonic-gate /* 5767c478bd9Sstevel@tonic-gate * Get the data buffer for the associated string table. 5777c478bd9Sstevel@tonic-gate */ 5787c478bd9Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 5797c478bd9Sstevel@tonic-gate num = shdr.sh_info; 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5827c478bd9Sstevel@tonic-gate vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 583090a8d9eSAli Bahrami GElf_Vernaux *vnap; 584090a8d9eSAli Bahrami Word ndx; 585*d444b03eSAli Bahrami const char *needobj, *dep; 586*d444b03eSAli Bahrami int started = 0, listcnt = 0; 5877c478bd9Sstevel@tonic-gate 588090a8d9eSAli Bahrami vnap = (GElf_Vernaux *) ((uintptr_t)vnd + vnd->vn_aux); 589090a8d9eSAli Bahrami 590090a8d9eSAli Bahrami /* Obtain the needed object file name */ 591090a8d9eSAli Bahrami needobj = (char *)(strs + vnd->vn_file); 5927c478bd9Sstevel@tonic-gate 5937c478bd9Sstevel@tonic-gate error = 1; 5947c478bd9Sstevel@tonic-gate 595090a8d9eSAli Bahrami /* Process the versions needed from this object */ 596090a8d9eSAli Bahrami for (ndx = 0; ndx < vnd->vn_cnt; ndx++, 597090a8d9eSAli Bahrami vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) { 598090a8d9eSAli Bahrami Conv_ver_flags_buf_t ver_flags_buf; 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate dep = (char *)(strs + vnap->vna_name); 6017c478bd9Sstevel@tonic-gate 602090a8d9eSAli Bahrami if (!match(needobj, dep, vnap->vna_other)) 603090a8d9eSAli Bahrami continue; 6047c478bd9Sstevel@tonic-gate 605090a8d9eSAli Bahrami if (show) { 606090a8d9eSAli Bahrami if ((started == 0) || (vsdata != NULL)) { 607090a8d9eSAli Bahrami /* 608090a8d9eSAli Bahrami * If one-line ouput is called for 609090a8d9eSAli Bahrami * display the filename being processed. 610090a8d9eSAli Bahrami */ 611090a8d9eSAli Bahrami if (oflag && show) 612090a8d9eSAli Bahrami (void) printf( 613090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_OFIL), 614090a8d9eSAli Bahrami file); 615090a8d9eSAli Bahrami 616090a8d9eSAli Bahrami (void) printf( 617090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_BEGIN), 618090a8d9eSAli Bahrami needobj); 619090a8d9eSAli Bahrami started = 1; 620090a8d9eSAli Bahrami } 621090a8d9eSAli Bahrami 622090a8d9eSAli Bahrami /* 623090a8d9eSAli Bahrami * If not showing symbols, only show INFO 624090a8d9eSAli Bahrami * versions in verbose mode. They don't 625090a8d9eSAli Bahrami * actually contribute to the version 626090a8d9eSAli Bahrami * interface as seen by rtld, so listing them 627090a8d9eSAli Bahrami * without qualification can be misleading. 628090a8d9eSAli Bahrami */ 629090a8d9eSAli Bahrami if (vflag || (vsdata != NULL) || 630090a8d9eSAli Bahrami (alist_nitems(match_list) != 0) || 631090a8d9eSAli Bahrami !(vnap->vna_flags & VER_FLG_INFO)) { 632*d444b03eSAli Bahrami const char *fmt = (listcnt == 0) ? 633*d444b03eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_FIRST) : 634*d444b03eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_NEXT); 635*d444b03eSAli Bahrami 636*d444b03eSAli Bahrami if (vsdata == NULL) 637*d444b03eSAli Bahrami listcnt++; 638090a8d9eSAli Bahrami (void) printf(fmt, dep); 639090a8d9eSAli Bahrami 640090a8d9eSAli Bahrami /* Show non-zero flags */ 641090a8d9eSAli Bahrami if (vflag && (vnap->vna_flags != 0)) 642090a8d9eSAli Bahrami (void) printf( 643090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_VER_FLG), 644090a8d9eSAli Bahrami conv_ver_flags( 645090a8d9eSAli Bahrami vnap->vna_flags, 646090a8d9eSAli Bahrami CONV_FMT_NOBKT, 647090a8d9eSAli Bahrami &ver_flags_buf)); 648090a8d9eSAli Bahrami } 649090a8d9eSAli Bahrami if (vsdata != NULL) 650090a8d9eSAli Bahrami (void) printf(oflag ? 651090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_END_SEM) : 652090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_END_COL)); 653090a8d9eSAli Bahrami } 654090a8d9eSAli Bahrami 655090a8d9eSAli Bahrami /* 656090a8d9eSAli Bahrami * If we are showing symbols, and vna_other is 657090a8d9eSAli Bahrami * non-zero, list them here. 658090a8d9eSAli Bahrami * 659090a8d9eSAli Bahrami * A value of 0 means that this object uses 660090a8d9eSAli Bahrami * traditional Solaris versioning rules, under 661090a8d9eSAli Bahrami * which VERSYM does not contain indexes to VERNEED 662090a8d9eSAli Bahrami * records. In this case, there is nothing to show. 663090a8d9eSAli Bahrami */ 664090a8d9eSAli Bahrami if (vsdata && (vnap->vna_other > 0)) 665090a8d9eSAli Bahrami gvers_syms(vsdata, vnap->vna_other, 666090a8d9eSAli Bahrami dep, needobj, file); 6677c478bd9Sstevel@tonic-gate } 668090a8d9eSAli Bahrami if (show && started && (vsdata == NULL)) 669090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LIST_END_SEM)); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate return (error); 6727c478bd9Sstevel@tonic-gate } 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate /* 675090a8d9eSAli Bahrami * Return a GVer_desc descriptor for the given version if one 676090a8d9eSAli Bahrami * exists. 677090a8d9eSAli Bahrami * 678090a8d9eSAli Bahrami * entry: 679090a8d9eSAli Bahrami * name - Version name 680090a8d9eSAli Bahrami * hash - ELF hash of name 681090a8d9eSAli Bahrami * lst - APlist of existing descriptors. 682090a8d9eSAli Bahrami * file - Object file containing the version 683090a8d9eSAli Bahrami * 684090a8d9eSAli Bahrami * exit: 685090a8d9eSAli Bahrami * Return the corresponding GVer_desc struct if it 686090a8d9eSAli Bahrami * exists, and NULL otherwise. 6877c478bd9Sstevel@tonic-gate */ 6887c478bd9Sstevel@tonic-gate static GVer_desc * 689090a8d9eSAli Bahrami gvers_find(const char *name, unsigned long hash, APlist *lst) 6907c478bd9Sstevel@tonic-gate { 691090a8d9eSAli Bahrami Aliste idx; 6927c478bd9Sstevel@tonic-gate GVer_desc *vdp; 6937c478bd9Sstevel@tonic-gate 694090a8d9eSAli Bahrami for (APLIST_TRAVERSE(lst, idx, vdp)) 695090a8d9eSAli Bahrami if ((vdp->vd_hash == hash) && 696090a8d9eSAli Bahrami (strcmp(vdp->vd_name, name) == 0)) 6977c478bd9Sstevel@tonic-gate return (vdp); 698090a8d9eSAli Bahrami 699090a8d9eSAli Bahrami return (NULL); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 702090a8d9eSAli Bahrami /* 703090a8d9eSAli Bahrami * Return a GVer_desc descriptor for the given version. 704090a8d9eSAli Bahrami * 705090a8d9eSAli Bahrami * entry: 706090a8d9eSAli Bahrami * name - Version name 707090a8d9eSAli Bahrami * hash - ELF hash of name 708090a8d9eSAli Bahrami * lst - List of existing descriptors. 709090a8d9eSAli Bahrami * file - Object file containing the version 710090a8d9eSAli Bahrami * 711090a8d9eSAli Bahrami * exit: 712090a8d9eSAli Bahrami * Return the corresponding GVer_desc struct. If the 713090a8d9eSAli Bahrami * descriptor does not already exist, it is created. 714090a8d9eSAli Bahrami * On error, a fatal error is issued and the process exits. 715090a8d9eSAli Bahrami */ 7167c478bd9Sstevel@tonic-gate static GVer_desc * 717090a8d9eSAli Bahrami gvers_desc(const char *name, unsigned long hash, APlist **lst, const char *file) 7187c478bd9Sstevel@tonic-gate { 7197c478bd9Sstevel@tonic-gate GVer_desc *vdp; 7207c478bd9Sstevel@tonic-gate 721090a8d9eSAli Bahrami if ((vdp = gvers_find(name, hash, *lst)) == NULL) { 722090a8d9eSAli Bahrami if ((vdp = calloc(sizeof (GVer_desc), 1)) == NULL) { 7237c478bd9Sstevel@tonic-gate int err = errno; 7247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 7257c478bd9Sstevel@tonic-gate file, strerror(err)); 7267c478bd9Sstevel@tonic-gate exit(1); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate vdp->vd_name = name; 7307c478bd9Sstevel@tonic-gate vdp->vd_hash = hash; 7317c478bd9Sstevel@tonic-gate 732090a8d9eSAli Bahrami pvs_aplist_append(lst, vdp, file); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate return (vdp); 7357c478bd9Sstevel@tonic-gate } 7367c478bd9Sstevel@tonic-gate 737090a8d9eSAli Bahrami /* 738090a8d9eSAli Bahrami * Insert a version dependency for the given GVer_desc descriptor. 739090a8d9eSAli Bahrami * 740090a8d9eSAli Bahrami * entry: 741090a8d9eSAli Bahrami * name - Dependency version name 742090a8d9eSAli Bahrami * hash - ELF hash of name 743090a8d9eSAli Bahrami * lst - List of existing descriptors. 744090a8d9eSAli Bahrami * vdp - Existing version descriptor to which the dependency 745090a8d9eSAli Bahrami * is to be added. 746090a8d9eSAli Bahrami * file - Object file containing the version 747090a8d9eSAli Bahrami * 748090a8d9eSAli Bahrami * exit: 749090a8d9eSAli Bahrami * A descriptor for the dependency version is looked up 750090a8d9eSAli Bahrami * (created if necessary), and then added to the dependency 751090a8d9eSAli Bahrami * list for vdp. Returns the dependency descriptor. On error, 752090a8d9eSAli Bahrami * a fatal error is issued and the process exits. 753090a8d9eSAli Bahrami */ 7547c478bd9Sstevel@tonic-gate static GVer_desc * 755090a8d9eSAli Bahrami gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, APlist **lst, 7567c478bd9Sstevel@tonic-gate const char *file) 7577c478bd9Sstevel@tonic-gate { 7587c478bd9Sstevel@tonic-gate GVer_desc *_vdp; 7597c478bd9Sstevel@tonic-gate 760090a8d9eSAli Bahrami _vdp = gvers_desc(name, hash, lst, file); 761090a8d9eSAli Bahrami pvs_aplist_append(&vdp->vd_deps, _vdp, file); 7627c478bd9Sstevel@tonic-gate return (vdp); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate static void 766090a8d9eSAli Bahrami gvers_derefer(GVer_desc *vdp, int weak) 7677c478bd9Sstevel@tonic-gate { 768090a8d9eSAli Bahrami Aliste idx; 769090a8d9eSAli Bahrami GVer_desc *_vdp; 7707c478bd9Sstevel@tonic-gate 7717c478bd9Sstevel@tonic-gate /* 7727c478bd9Sstevel@tonic-gate * If the head of the list was a weak then we only clear out 7737c478bd9Sstevel@tonic-gate * weak dependencies, but if the head of the list was 'strong' 7747c478bd9Sstevel@tonic-gate * we clear the REFER bit on all dependencies. 7757c478bd9Sstevel@tonic-gate */ 7767c478bd9Sstevel@tonic-gate if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak)) 7777c478bd9Sstevel@tonic-gate vdp->vd_flags &= ~FLG_VER_AVAIL; 7787c478bd9Sstevel@tonic-gate 779090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) 7807c478bd9Sstevel@tonic-gate gvers_derefer(_vdp, weak); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate static void 785090a8d9eSAli Bahrami recurse_syms(const Gver_sym_data *vsdata, GVer_desc *vdp, const char *file) 7867c478bd9Sstevel@tonic-gate { 787090a8d9eSAli Bahrami Aliste idx; 7887c478bd9Sstevel@tonic-gate GVer_desc *_vdp; 7897c478bd9Sstevel@tonic-gate 790090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) { 7917c478bd9Sstevel@tonic-gate if (!oflag) 792090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNCO), _vdp->vd_name); 793090a8d9eSAli Bahrami gvers_syms(vsdata, _vdp->vd_ndx, _vdp->vd_name, NULL, file); 794090a8d9eSAli Bahrami if (aplist_nitems(_vdp->vd_deps) != 0) 795090a8d9eSAli Bahrami recurse_syms(vsdata, _vdp, file); 7967c478bd9Sstevel@tonic-gate } 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate /* 8017c478bd9Sstevel@tonic-gate * Print the files version definition sections. 8027c478bd9Sstevel@tonic-gate */ 8037c478bd9Sstevel@tonic-gate static int 804090a8d9eSAli Bahrami gvers_def(Cache *cache, Cache *def, const Gver_sym_data *vsdata, 805090a8d9eSAli Bahrami const char *file) 8067c478bd9Sstevel@tonic-gate { 8077c478bd9Sstevel@tonic-gate unsigned int num, _num; 8087c478bd9Sstevel@tonic-gate char *strs; 8097c478bd9Sstevel@tonic-gate GElf_Verdef *vdf = def->c_data->d_buf; 8107c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 811090a8d9eSAli Bahrami GVer_desc *vdp, *bvdp = NULL; 812090a8d9eSAli Bahrami Aliste idx1; 813090a8d9eSAli Bahrami APlist *verdefs = NULL; 8147c478bd9Sstevel@tonic-gate int error = 0; 8157c478bd9Sstevel@tonic-gate 8167c478bd9Sstevel@tonic-gate /* 8177c478bd9Sstevel@tonic-gate * Verify the version revision. We only check the first version 8187c478bd9Sstevel@tonic-gate * structure as it is assumed all other version structures in this 8197c478bd9Sstevel@tonic-gate * data section will be of the same revision. 8207c478bd9Sstevel@tonic-gate */ 8217c478bd9Sstevel@tonic-gate if (vdf->vd_version > VER_DEF_CURRENT) { 8227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 8237c478bd9Sstevel@tonic-gate vdf->vd_version, VER_DEF_CURRENT); 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate 8267c478bd9Sstevel@tonic-gate /* 8277c478bd9Sstevel@tonic-gate * Get the data buffer for the associated string table. 8287c478bd9Sstevel@tonic-gate */ 8297c478bd9Sstevel@tonic-gate (void) gelf_getshdr(def->c_scn, &shdr); 8307c478bd9Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 8317c478bd9Sstevel@tonic-gate num = shdr.sh_info; 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate /* 8347c478bd9Sstevel@tonic-gate * Process the version definitions placing each on a version dependency 8357c478bd9Sstevel@tonic-gate * list. 8367c478bd9Sstevel@tonic-gate */ 8377c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 8387c478bd9Sstevel@tonic-gate vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 8397c478bd9Sstevel@tonic-gate GElf_Half cnt = vdf->vd_cnt; 8407c478bd9Sstevel@tonic-gate GElf_Half ndx = vdf->vd_ndx; 841090a8d9eSAli Bahrami GElf_Verdaux *vdap; 8427c478bd9Sstevel@tonic-gate const char *_name; 8437c478bd9Sstevel@tonic-gate 844090a8d9eSAli Bahrami vdap = (GElf_Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 845090a8d9eSAli Bahrami 8467c478bd9Sstevel@tonic-gate /* 8477c478bd9Sstevel@tonic-gate * Determine the version name and any dependencies. 8487c478bd9Sstevel@tonic-gate */ 8497c478bd9Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 8507c478bd9Sstevel@tonic-gate 851090a8d9eSAli Bahrami vdp = gvers_desc(_name, elf_hash(_name), &verdefs, file); 8527c478bd9Sstevel@tonic-gate vdp->vd_ndx = ndx; 8537c478bd9Sstevel@tonic-gate vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL; 8547c478bd9Sstevel@tonic-gate 8557c478bd9Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next); 8567c478bd9Sstevel@tonic-gate for (cnt--; cnt; cnt--, 8577c478bd9Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) { 8587c478bd9Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 8597c478bd9Sstevel@tonic-gate if (gvers_depend(_name, elf_hash(_name), vdp, 860090a8d9eSAli Bahrami &verdefs, file) == NULL) 8617c478bd9Sstevel@tonic-gate return (0); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* 8657c478bd9Sstevel@tonic-gate * Remember the base version for possible later use. 8667c478bd9Sstevel@tonic-gate */ 8677c478bd9Sstevel@tonic-gate if (ndx == VER_NDX_GLOBAL) 8687c478bd9Sstevel@tonic-gate bvdp = vdp; 8697c478bd9Sstevel@tonic-gate } 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate /* 8727c478bd9Sstevel@tonic-gate * Normalize the dependency list if required. 8737c478bd9Sstevel@tonic-gate */ 8747c478bd9Sstevel@tonic-gate if (nflag) { 875090a8d9eSAli Bahrami for (APLIST_TRAVERSE(verdefs, idx1, vdp)) { 876090a8d9eSAli Bahrami Aliste idx2; 877090a8d9eSAli Bahrami GVer_desc *_vdp; 8787c478bd9Sstevel@tonic-gate int type = vdp->vd_flags & VER_FLG_WEAK; 8797c478bd9Sstevel@tonic-gate 880090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) 8817c478bd9Sstevel@tonic-gate gvers_derefer(_vdp, type); 8827c478bd9Sstevel@tonic-gate } 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* 8857c478bd9Sstevel@tonic-gate * Always dereference the base version. 8867c478bd9Sstevel@tonic-gate */ 8877c478bd9Sstevel@tonic-gate if (bvdp) 8887c478bd9Sstevel@tonic-gate bvdp->vd_flags &= ~FLG_VER_AVAIL; 8897c478bd9Sstevel@tonic-gate } 8907c478bd9Sstevel@tonic-gate 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * Traverse the dependency list and print out the appropriate 8947c478bd9Sstevel@tonic-gate * information. 8957c478bd9Sstevel@tonic-gate */ 896090a8d9eSAli Bahrami for (APLIST_TRAVERSE(verdefs, idx1, vdp)) { 897090a8d9eSAli Bahrami Aliste idx2; 898090a8d9eSAli Bahrami GVer_desc *_vdp; 8997c478bd9Sstevel@tonic-gate int count; 9007c478bd9Sstevel@tonic-gate 901090a8d9eSAli Bahrami if (!match(NULL, vdp->vd_name, vdp->vd_ndx)) 9027c478bd9Sstevel@tonic-gate continue; 903090a8d9eSAli Bahrami if ((alist_nitems(match_list) == 0) && 904090a8d9eSAli Bahrami !(vdp->vd_flags & FLG_VER_AVAIL)) 9057c478bd9Sstevel@tonic-gate continue; 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate error = 1; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate if (vflag) { 9107c478bd9Sstevel@tonic-gate /* 9117c478bd9Sstevel@tonic-gate * If the verbose flag is set determine if this version 9127c478bd9Sstevel@tonic-gate * has a `weak' attribute, and print any version 9137c478bd9Sstevel@tonic-gate * dependencies this version inherits. 9147c478bd9Sstevel@tonic-gate */ 9157c478bd9Sstevel@tonic-gate if (oflag) 916090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_OFIL), file); 917090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_VER_NAME), vdp->vd_name); 918090a8d9eSAli Bahrami if ((vdp->vd_flags & MSK_VER_USER) != 0) { 919090a8d9eSAli Bahrami Conv_ver_flags_buf_t ver_flags_buf; 920090a8d9eSAli Bahrami 921090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_VER_FLG), 922090a8d9eSAli Bahrami conv_ver_flags( 923090a8d9eSAli Bahrami vdp->vd_flags & MSK_VER_USER, 924090a8d9eSAli Bahrami CONV_FMT_NOBKT, &ver_flags_buf)); 925090a8d9eSAli Bahrami } 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate count = 1; 928090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) { 9297c478bd9Sstevel@tonic-gate const char *_name = _vdp->vd_name; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate if (count++ == 1) { 932090a8d9eSAli Bahrami 9337c478bd9Sstevel@tonic-gate if (oflag) 934090a8d9eSAli Bahrami (void) printf( 935090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_IN_OFLG), 936090a8d9eSAli Bahrami _name); 9377c478bd9Sstevel@tonic-gate else if (vdp->vd_flags & VER_FLG_WEAK) 938090a8d9eSAli Bahrami (void) printf( 939090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_IN_WEAK), 940090a8d9eSAli Bahrami _name); 9417c478bd9Sstevel@tonic-gate else 942090a8d9eSAli Bahrami (void) printf( 943090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_IN), 9447c478bd9Sstevel@tonic-gate _name); 9457c478bd9Sstevel@tonic-gate } else 946090a8d9eSAli Bahrami (void) printf( 947090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_NEXT), _name); 9487c478bd9Sstevel@tonic-gate } 9497c478bd9Sstevel@tonic-gate 9507c478bd9Sstevel@tonic-gate if (count != 1) 951090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_IN_END)); 9527c478bd9Sstevel@tonic-gate 953090a8d9eSAli Bahrami if (vsdata && !oflag) 954090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_COL_NL)); 9557c478bd9Sstevel@tonic-gate else 956090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SEM_NL)); 9577c478bd9Sstevel@tonic-gate } else { 958090a8d9eSAli Bahrami if (vsdata && !oflag) 959090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNCO), 960090a8d9eSAli Bahrami vdp->vd_name); 961090a8d9eSAli Bahrami else if (!vsdata) { 9627c478bd9Sstevel@tonic-gate if (oflag) 963090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_OFIL), 964090a8d9eSAli Bahrami file); 965090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNSE), 966090a8d9eSAli Bahrami vdp->vd_name); 9677c478bd9Sstevel@tonic-gate } 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate 970090a8d9eSAli Bahrami /* If we are not printing symbols, we're done */ 971090a8d9eSAli Bahrami if (vsdata == NULL) 9727c478bd9Sstevel@tonic-gate continue; 9737c478bd9Sstevel@tonic-gate 9747c478bd9Sstevel@tonic-gate /* 975090a8d9eSAli Bahrami * If a specific version to match has been specified then 976090a8d9eSAli Bahrami * display any of its own symbols plus any inherited from 977090a8d9eSAli Bahrami * other versions. Otherwise simply print out the symbols 978090a8d9eSAli Bahrami * for this version. 9797c478bd9Sstevel@tonic-gate */ 980090a8d9eSAli Bahrami gvers_syms(vsdata, vdp->vd_ndx, vdp->vd_name, NULL, file); 981090a8d9eSAli Bahrami if (alist_nitems(match_list) != 0) { 982090a8d9eSAli Bahrami recurse_syms(vsdata, vdp, file); 9837c478bd9Sstevel@tonic-gate 9847c478bd9Sstevel@tonic-gate /* 985090a8d9eSAli Bahrami * If the verbose flag is set, and this is not 986090a8d9eSAli Bahrami * the base version, then add the base version as a 987090a8d9eSAli Bahrami * dependency. 9887c478bd9Sstevel@tonic-gate */ 989090a8d9eSAli Bahrami if (vflag && bvdp && 990090a8d9eSAli Bahrami !match(NULL, bvdp->vd_name, bvdp->vd_ndx)) { 9917c478bd9Sstevel@tonic-gate if (!oflag) 992090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNCO), 993090a8d9eSAli Bahrami bvdp->vd_name); 994090a8d9eSAli Bahrami gvers_syms(vsdata, bvdp->vd_ndx, 995090a8d9eSAli Bahrami bvdp->vd_name, NULL, file); 9967c478bd9Sstevel@tonic-gate } 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate return (error); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate int 10037c478bd9Sstevel@tonic-gate main(int argc, char **argv, char **envp) 10047c478bd9Sstevel@tonic-gate { 10057c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 10067c478bd9Sstevel@tonic-gate Elf *elf; 10077c478bd9Sstevel@tonic-gate Elf_Scn *scn; 10087c478bd9Sstevel@tonic-gate Elf_Data *data; 10097c478bd9Sstevel@tonic-gate GElf_Ehdr ehdr; 10107c478bd9Sstevel@tonic-gate int nfile, var; 10117c478bd9Sstevel@tonic-gate char *names; 10127c478bd9Sstevel@tonic-gate Cache *cache, *_cache; 10137c478bd9Sstevel@tonic-gate Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc; 10147c478bd9Sstevel@tonic-gate int error = 0; 1015090a8d9eSAli Bahrami Gver_sym_data vsdata_s; 1016090a8d9eSAli Bahrami const Gver_sym_data *vsdata = NULL; 10177c478bd9Sstevel@tonic-gate 10187c478bd9Sstevel@tonic-gate /* 10197c478bd9Sstevel@tonic-gate * Check for a binary that better fits this architecture. 10207c478bd9Sstevel@tonic-gate */ 10217010c12aSrie (void) conv_check_native(argv, envp); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * Establish locale. 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 10277c478bd9Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 10287c478bd9Sstevel@tonic-gate 10297c478bd9Sstevel@tonic-gate cname = argv[0]; 10307c478bd9Sstevel@tonic-gate Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0; 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate opterr = 0; 1033090a8d9eSAli Bahrami while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 10347c478bd9Sstevel@tonic-gate switch (var) { 10357c478bd9Sstevel@tonic-gate case 'C': 10367c478bd9Sstevel@tonic-gate Cflag = USR_DEFINED; 10377c478bd9Sstevel@tonic-gate break; 10387c478bd9Sstevel@tonic-gate case 'd': 10397c478bd9Sstevel@tonic-gate dflag = USR_DEFINED; 10407c478bd9Sstevel@tonic-gate break; 10417c478bd9Sstevel@tonic-gate case 'l': 1042090a8d9eSAli Bahrami lflag = sflag = USR_DEFINED; 10437c478bd9Sstevel@tonic-gate break; 10447c478bd9Sstevel@tonic-gate case 'n': 10457c478bd9Sstevel@tonic-gate nflag = USR_DEFINED; 10467c478bd9Sstevel@tonic-gate break; 10477c478bd9Sstevel@tonic-gate case 'o': 10487c478bd9Sstevel@tonic-gate oflag = USR_DEFINED; 10497c478bd9Sstevel@tonic-gate break; 10507c478bd9Sstevel@tonic-gate case 'r': 10517c478bd9Sstevel@tonic-gate rflag = USR_DEFINED; 10527c478bd9Sstevel@tonic-gate break; 10537c478bd9Sstevel@tonic-gate case 's': 10547c478bd9Sstevel@tonic-gate sflag = USR_DEFINED; 10557c478bd9Sstevel@tonic-gate break; 10567c478bd9Sstevel@tonic-gate case 'v': 10577c478bd9Sstevel@tonic-gate vflag = USR_DEFINED; 10587c478bd9Sstevel@tonic-gate break; 1059090a8d9eSAli Bahrami case 'I': 10607c478bd9Sstevel@tonic-gate case 'N': 1061090a8d9eSAli Bahrami add_match_record(var, optarg); 10627c478bd9Sstevel@tonic-gate break; 10637c478bd9Sstevel@tonic-gate case '?': 10647c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 10657c478bd9Sstevel@tonic-gate cname); 10667c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL)); 10677c478bd9Sstevel@tonic-gate exit(1); 10687c478bd9Sstevel@tonic-gate default: 10697c478bd9Sstevel@tonic-gate break; 10707c478bd9Sstevel@tonic-gate } 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate /* 10747c478bd9Sstevel@tonic-gate * No files specified on the command line? 10757c478bd9Sstevel@tonic-gate */ 10767c478bd9Sstevel@tonic-gate if ((nfile = argc - optind) == 0) { 10777c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 10787c478bd9Sstevel@tonic-gate exit(1); 10797c478bd9Sstevel@tonic-gate } 10807c478bd9Sstevel@tonic-gate 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * By default print both version definitions and needed dependencies. 10837c478bd9Sstevel@tonic-gate */ 1084090a8d9eSAli Bahrami if ((dflag == 0) && (rflag == 0) && (lflag == 0)) 10857c478bd9Sstevel@tonic-gate dflag = rflag = DEF_DEFINED; 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * Open the input file and initialize the elf interface. 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate for (; optind < argc; optind++) { 10917c478bd9Sstevel@tonic-gate int derror = 0, nerror = 0, err; 10927c478bd9Sstevel@tonic-gate const char *file = argv[optind]; 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate if ((var = open(file, O_RDONLY)) == -1) { 10957c478bd9Sstevel@tonic-gate err = errno; 10967c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 10977c478bd9Sstevel@tonic-gate cname, file, strerror(err)); 10987c478bd9Sstevel@tonic-gate error = 1; 10997c478bd9Sstevel@tonic-gate continue; 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 11027c478bd9Sstevel@tonic-gate if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) { 11037c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname, 11047c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11057c478bd9Sstevel@tonic-gate error = 1; 11067c478bd9Sstevel@tonic-gate (void) close(var); 11077c478bd9Sstevel@tonic-gate continue; 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate if (elf_kind(elf) != ELF_K_ELF) { 11107c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname, 11117c478bd9Sstevel@tonic-gate file); 11127c478bd9Sstevel@tonic-gate error = 1; 11137c478bd9Sstevel@tonic-gate (void) close(var); 11147c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11157c478bd9Sstevel@tonic-gate continue; 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) { 11187c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname, 11197c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11207c478bd9Sstevel@tonic-gate error = 1; 11217c478bd9Sstevel@tonic-gate (void) close(var); 11227c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11237c478bd9Sstevel@tonic-gate continue; 11247c478bd9Sstevel@tonic-gate } 11257c478bd9Sstevel@tonic-gate 11267c478bd9Sstevel@tonic-gate /* 11277c478bd9Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required 11287c478bd9Sstevel@tonic-gate * section name strings. 11297c478bd9Sstevel@tonic-gate */ 11307c478bd9Sstevel@tonic-gate if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) { 11317c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname, 11327c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11337c478bd9Sstevel@tonic-gate error = 1; 11347c478bd9Sstevel@tonic-gate (void) close(var); 11357c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11367c478bd9Sstevel@tonic-gate continue; 11377c478bd9Sstevel@tonic-gate } 11387c478bd9Sstevel@tonic-gate if ((data = elf_getdata(scn, NULL)) == NULL) { 11397c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname, 11407c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11417c478bd9Sstevel@tonic-gate error = 1; 11427c478bd9Sstevel@tonic-gate (void) close(var); 11437c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11447c478bd9Sstevel@tonic-gate continue; 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate names = data->d_buf; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate /* 11497c478bd9Sstevel@tonic-gate * Fill in the cache descriptor with information for each 11507c478bd9Sstevel@tonic-gate * section we might need. We probably only need to save 11517c478bd9Sstevel@tonic-gate * read-only allocable sections as this is where the version 11527c478bd9Sstevel@tonic-gate * structures and their associated symbols and strings live. 11537c478bd9Sstevel@tonic-gate * However, God knows what someone can do with a mapfile, and 11547c478bd9Sstevel@tonic-gate * as elf_begin has already gone through all the overhead we 11557c478bd9Sstevel@tonic-gate * might as well set up the cache for every section. 11567c478bd9Sstevel@tonic-gate */ 1157090a8d9eSAli Bahrami if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == NULL) { 11587c478bd9Sstevel@tonic-gate int err = errno; 11597c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 11607c478bd9Sstevel@tonic-gate file, strerror(err)); 11617c478bd9Sstevel@tonic-gate exit(1); 11627c478bd9Sstevel@tonic-gate } 11637c478bd9Sstevel@tonic-gate 1164090a8d9eSAli Bahrami _cache_def = _cache_need = _cache_sym = _cache_loc = NULL; 11657c478bd9Sstevel@tonic-gate _cache = cache; 11667c478bd9Sstevel@tonic-gate _cache++; 11677c478bd9Sstevel@tonic-gate for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) { 11687c478bd9Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL) { 11697c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11707c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETSHDR), cname, file, 11717c478bd9Sstevel@tonic-gate elf_errmsg(elf_errno())); 11727c478bd9Sstevel@tonic-gate error = 1; 11737c478bd9Sstevel@tonic-gate continue; 11747c478bd9Sstevel@tonic-gate } 11757c478bd9Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == 11767c478bd9Sstevel@tonic-gate NULL) { 11777c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11787c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETDATA), cname, file, 11797c478bd9Sstevel@tonic-gate elf_errmsg(elf_errno())); 11807c478bd9Sstevel@tonic-gate error = 1; 11817c478bd9Sstevel@tonic-gate continue; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate _cache->c_scn = scn; 11847c478bd9Sstevel@tonic-gate _cache->c_name = names + shdr.sh_name; 11857c478bd9Sstevel@tonic-gate 11867c478bd9Sstevel@tonic-gate /* 11877c478bd9Sstevel@tonic-gate * Remember the version sections and symbol table. 11887c478bd9Sstevel@tonic-gate */ 11899039eeafSab switch (shdr.sh_type) { 11909039eeafSab case SHT_SUNW_verdef: 11919039eeafSab if (dflag) 11929039eeafSab _cache_def = _cache; 11939039eeafSab break; 11949039eeafSab case SHT_SUNW_verneed: 11959039eeafSab if (rflag) 11969039eeafSab _cache_need = _cache; 11979039eeafSab break; 11989039eeafSab case SHT_SUNW_versym: 11999039eeafSab if (sflag) 12009039eeafSab _cache_sym = _cache; 12019039eeafSab break; 12029039eeafSab case SHT_SYMTAB: 12039039eeafSab if (lflag) 12049039eeafSab _cache_loc = _cache; 12059039eeafSab break; 12069039eeafSab } 12077c478bd9Sstevel@tonic-gate } 12087c478bd9Sstevel@tonic-gate 12097c478bd9Sstevel@tonic-gate /* 12107c478bd9Sstevel@tonic-gate * Before printing anything out determine if any warnings are 12117c478bd9Sstevel@tonic-gate * necessary. 12127c478bd9Sstevel@tonic-gate */ 1213090a8d9eSAli Bahrami if (lflag && (_cache_loc == NULL)) { 12147c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), 12157c478bd9Sstevel@tonic-gate cname, file); 12167c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB)); 12177c478bd9Sstevel@tonic-gate } 12187c478bd9Sstevel@tonic-gate 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * If there is more than one input file, and we're not printing 12217c478bd9Sstevel@tonic-gate * one-line output, display the filename being processed. 12227c478bd9Sstevel@tonic-gate */ 12237c478bd9Sstevel@tonic-gate if ((nfile > 1) && !oflag) 1224090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_FILE), file); 1225090a8d9eSAli Bahrami 1226090a8d9eSAli Bahrami /* 1227090a8d9eSAli Bahrami * If we're printing symbols, then collect the data 1228090a8d9eSAli Bahrami * necessary to do that. 1229090a8d9eSAli Bahrami */ 1230090a8d9eSAli Bahrami if (_cache_sym != NULL) { 1231090a8d9eSAli Bahrami vsdata = &vsdata_s; 1232090a8d9eSAli Bahrami (void) gelf_getshdr(_cache_sym->c_scn, &shdr); 1233090a8d9eSAli Bahrami vsdata_s.vsd_vsp = 1234090a8d9eSAli Bahrami (GElf_Versym *)_cache_sym->c_data->d_buf; 1235090a8d9eSAli Bahrami vsdata_s.vsd_sym_data = cache[shdr.sh_link].c_data; 1236090a8d9eSAli Bahrami (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr); 1237090a8d9eSAli Bahrami vsdata_s.vsd_symn = shdr.sh_size / shdr.sh_entsize; 1238090a8d9eSAli Bahrami vsdata_s.vsd_strs = 1239090a8d9eSAli Bahrami (const char *)cache[shdr.sh_link].c_data->d_buf; 1240090a8d9eSAli Bahrami } 1241090a8d9eSAli Bahrami 12427c478bd9Sstevel@tonic-gate 12437c478bd9Sstevel@tonic-gate /* 12447c478bd9Sstevel@tonic-gate * Print the files version needed sections. 12457c478bd9Sstevel@tonic-gate */ 12467c478bd9Sstevel@tonic-gate if (_cache_need) 1247090a8d9eSAli Bahrami nerror = gvers_need(cache, _cache_need, vsdata, file); 12487c478bd9Sstevel@tonic-gate 12497c478bd9Sstevel@tonic-gate /* 12507c478bd9Sstevel@tonic-gate * Print the files version definition sections. 12517c478bd9Sstevel@tonic-gate */ 12527c478bd9Sstevel@tonic-gate if (_cache_def) 1253090a8d9eSAli Bahrami derror = gvers_def(cache, _cache_def, vsdata, file); 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate /* 12567c478bd9Sstevel@tonic-gate * Print any local symbol reductions. 12577c478bd9Sstevel@tonic-gate */ 12587c478bd9Sstevel@tonic-gate if (_cache_loc) 12597c478bd9Sstevel@tonic-gate sym_local(cache, _cache_loc, file); 12607c478bd9Sstevel@tonic-gate 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * Determine the error return. There are three conditions that 12637c478bd9Sstevel@tonic-gate * may produce an error (a non-zero return): 12647c478bd9Sstevel@tonic-gate * 12657c478bd9Sstevel@tonic-gate * o if the user specified -d and no version definitions 12667c478bd9Sstevel@tonic-gate * were found. 12677c478bd9Sstevel@tonic-gate * 12687c478bd9Sstevel@tonic-gate * o if the user specified -r and no version requirements 12697c478bd9Sstevel@tonic-gate * were found. 12707c478bd9Sstevel@tonic-gate * 12717c478bd9Sstevel@tonic-gate * o if the user specified neither -d or -r, (thus both are 12727c478bd9Sstevel@tonic-gate * enabled by default), and no version definitions or 12737c478bd9Sstevel@tonic-gate * version dependencies were found. 12747c478bd9Sstevel@tonic-gate */ 12757c478bd9Sstevel@tonic-gate if (((dflag == USR_DEFINED) && (derror == 0)) || 12767c478bd9Sstevel@tonic-gate ((rflag == USR_DEFINED) && (nerror == 0)) || 12777c478bd9Sstevel@tonic-gate (rflag && dflag && (derror == 0) && (nerror == 0))) 12787c478bd9Sstevel@tonic-gate error = 1; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate (void) close(var); 12817c478bd9Sstevel@tonic-gate (void) elf_end(elf); 12827c478bd9Sstevel@tonic-gate free(cache); 12837c478bd9Sstevel@tonic-gate } 12847c478bd9Sstevel@tonic-gate return (error); 12857c478bd9Sstevel@tonic-gate } 12867c478bd9Sstevel@tonic-gate 12877c478bd9Sstevel@tonic-gate const char * 12887c478bd9Sstevel@tonic-gate _pvs_msg(Msg mid) 12897c478bd9Sstevel@tonic-gate { 12907c478bd9Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 12917c478bd9Sstevel@tonic-gate } 1292