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 /* 23d444b03eSAli Bahrami * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*6a6cfa5dSJason King * Copyright 2019 Joyent, Inc. 267c478bd9Sstevel@tonic-gate */ 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Analyze the versioning information within a file. 307c478bd9Sstevel@tonic-gate * 31*6a6cfa5dSJason King * -C demangle symbol names. 327c478bd9Sstevel@tonic-gate * 337c478bd9Sstevel@tonic-gate * -d dump version definitions. 347c478bd9Sstevel@tonic-gate * 35090a8d9eSAli Bahrami * -l print reduced (local) symbols. Implies -s. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * -n normalize any version definitions. 387c478bd9Sstevel@tonic-gate * 397c478bd9Sstevel@tonic-gate * -o dump output in one-line fashion (more suitable for grep'ing 407c478bd9Sstevel@tonic-gate * and diff'ing). 417c478bd9Sstevel@tonic-gate * 427c478bd9Sstevel@tonic-gate * -r dump the version requirements on library dependencies 437c478bd9Sstevel@tonic-gate * 447c478bd9Sstevel@tonic-gate * -s display the symbols associated with each version definition. 457c478bd9Sstevel@tonic-gate * 467c478bd9Sstevel@tonic-gate * -v verbose output. With the -r and -d options any WEAK attribute 477c478bd9Sstevel@tonic-gate * is displayed. With the -d option, any version inheritance, 48090a8d9eSAli Bahrami * and the base version are displayed. With the -r option, 49090a8d9eSAli Bahrami * WEAK and INFO attributes are displayed. With the -s option 50090a8d9eSAli Bahrami * the version symbol is displayed. 51090a8d9eSAli Bahrami * 52090a8d9eSAli Bahrami * -I index only print the specifed version index, or index range. 537c478bd9Sstevel@tonic-gate * 547c478bd9Sstevel@tonic-gate * -N name only print the specifed `name'. 557c478bd9Sstevel@tonic-gate */ 567c478bd9Sstevel@tonic-gate #include <fcntl.h> 577c478bd9Sstevel@tonic-gate #include <stdio.h> 587c478bd9Sstevel@tonic-gate #include <libelf.h> 597c478bd9Sstevel@tonic-gate #include <link.h> 607c478bd9Sstevel@tonic-gate #include <stdlib.h> 617c478bd9Sstevel@tonic-gate #include <string.h> 627c478bd9Sstevel@tonic-gate #include <unistd.h> 637c478bd9Sstevel@tonic-gate #include <locale.h> 647c478bd9Sstevel@tonic-gate #include <errno.h> 655aefb655Srie #include <sgs.h> 665aefb655Srie #include <conv.h> 675aefb655Srie #include <gelf.h> 685aefb655Srie #include <debug.h> 69090a8d9eSAli Bahrami #include <ctype.h> 70090a8d9eSAli Bahrami #include <alist.h> 717c478bd9Sstevel@tonic-gate #include "msg.h" 727c478bd9Sstevel@tonic-gate 73090a8d9eSAli Bahrami /* 74090a8d9eSAli Bahrami * Define Alist initialization sizes. 75090a8d9eSAli Bahrami */ 76090a8d9eSAli Bahrami #define AL_CNT_MATCH_LIST 5 /* match_list initial alist count */ 77090a8d9eSAli Bahrami #define AL_CNT_GVER_DESC 25 /* version tracking descriptors */ 787c478bd9Sstevel@tonic-gate 797c478bd9Sstevel@tonic-gate typedef struct cache { 807c478bd9Sstevel@tonic-gate Elf_Scn *c_scn; 817c478bd9Sstevel@tonic-gate Elf_Data *c_data; 827c478bd9Sstevel@tonic-gate char *c_name; 837c478bd9Sstevel@tonic-gate } Cache; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate typedef struct gver_desc { 867c478bd9Sstevel@tonic-gate const char *vd_name; 877c478bd9Sstevel@tonic-gate unsigned long vd_hash; 887c478bd9Sstevel@tonic-gate GElf_Half vd_ndx; 897c478bd9Sstevel@tonic-gate GElf_Half vd_flags; 90090a8d9eSAli Bahrami APlist *vd_deps; 917c478bd9Sstevel@tonic-gate } GVer_desc; 927c478bd9Sstevel@tonic-gate 93090a8d9eSAli Bahrami /* Versym related data used by gvers_syms() */ 94090a8d9eSAli Bahrami typedef struct { 95*6a6cfa5dSJason King GElf_Versym *vsd_vsp; /* ptr to versym data */ 96090a8d9eSAli Bahrami Elf_Data *vsd_sym_data; /* ptr to symtab data */ 97090a8d9eSAli Bahrami Word vsd_symn; /* # of symbols in symtab */ 98090a8d9eSAli Bahrami const char *vsd_strs; /* string table data */ 99090a8d9eSAli Bahrami } Gver_sym_data; 100090a8d9eSAli Bahrami 101090a8d9eSAli Bahrami /* 102090a8d9eSAli Bahrami * Type used to manage -I and -N options: 103090a8d9eSAli Bahrami * 104090a8d9eSAli Bahrami * The -I option specifies a VERSYM index, or index range. The 105090a8d9eSAli Bahrami * result is to select the VERDEF or VERNEED records with 106090a8d9eSAli Bahrami * indexes that match those given. 107090a8d9eSAli Bahrami * 108090a8d9eSAli Bahrami * -N options come in two forms: 109090a8d9eSAli Bahrami * 110090a8d9eSAli Bahrami * 1) name 111090a8d9eSAli Bahrami * 2) needobj (version) 112090a8d9eSAli Bahrami * 113090a8d9eSAli Bahrami * The meaning of the first case depends on the type of 114090a8d9eSAli Bahrami * version record being matched: 115090a8d9eSAli Bahrami * 116090a8d9eSAli Bahrami * VERDEF - name is the name of a version defined 117090a8d9eSAli Bahrami * by the object being processed (i.e. SUNW_1.1). 118090a8d9eSAli Bahrami * 119090a8d9eSAli Bahrami * VERNEED - name is the name of the object file 120090a8d9eSAli Bahrami * on which the dependency exists (i.e. libc.so.1). 121090a8d9eSAli Bahrami * 122090a8d9eSAli Bahrami * -N options of the second form only apply to VERNEED records. 123090a8d9eSAli Bahrami * They are used to specify a version from a needed object. 124090a8d9eSAli Bahrami */ 125090a8d9eSAli Bahrami /* match_opt_t is used to note which match option was used */ 126090a8d9eSAli Bahrami typedef enum { 127090a8d9eSAli Bahrami MATCH_OPT_NAME, /* Record contains a name */ 128090a8d9eSAli Bahrami MATCH_OPT_NEED_VER, /* Record contains needed object and version */ 129090a8d9eSAli Bahrami MATCH_OPT_NDX, /* Record contains a single index */ 130090a8d9eSAli Bahrami MATCH_OPT_RANGE, /* Record contains an index range */ 131090a8d9eSAli Bahrami } match_opt_t; 132090a8d9eSAli Bahrami 133090a8d9eSAli Bahrami typedef struct { 134090a8d9eSAli Bahrami match_opt_t opt_type; 135090a8d9eSAli Bahrami union { 136090a8d9eSAli Bahrami struct { 137090a8d9eSAli Bahrami const char *version; /* MATCH_OPT_{NAME|NEED_VER} */ 138090a8d9eSAli Bahrami const char *needobj; /* MATCH_OPT_NEED_VER only */ 139090a8d9eSAli Bahrami } name; 140090a8d9eSAli Bahrami struct { 141090a8d9eSAli Bahrami int start; /* MATCH_OPT_{NDX|RANGE} */ 142090a8d9eSAli Bahrami int end; /* MATCH_OPT_RANGE only) */ 143090a8d9eSAli Bahrami } ndx; 144090a8d9eSAli Bahrami } value; 145090a8d9eSAli Bahrami } match_rec_t; 146090a8d9eSAli Bahrami 147090a8d9eSAli Bahrami 148090a8d9eSAli Bahrami 1497c478bd9Sstevel@tonic-gate static const char *cname; 1507c478bd9Sstevel@tonic-gate static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag; 151090a8d9eSAli Bahrami static Alist *match_list; 1527c478bd9Sstevel@tonic-gate 153090a8d9eSAli Bahrami /* Used to track whether an option defaulted to on, or was explicitly set */ 1547c478bd9Sstevel@tonic-gate #define DEF_DEFINED 1 1557c478bd9Sstevel@tonic-gate #define USR_DEFINED 2 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * Determine whether a symbol name should be demangled. 1597c478bd9Sstevel@tonic-gate */ 1607c478bd9Sstevel@tonic-gate static const char * 1617c478bd9Sstevel@tonic-gate demangle(const char *name) 1627c478bd9Sstevel@tonic-gate { 1637c478bd9Sstevel@tonic-gate if (Cflag) 1645aefb655Srie return (Elf_demangle_name(name)); 1657c478bd9Sstevel@tonic-gate else 1667c478bd9Sstevel@tonic-gate return (name); 1677c478bd9Sstevel@tonic-gate } 1687c478bd9Sstevel@tonic-gate 169090a8d9eSAli Bahrami /* 170090a8d9eSAli Bahrami * Append an item to the specified list, and return a pointer to the list 171090a8d9eSAli Bahrami * node created. 172090a8d9eSAli Bahrami * 173090a8d9eSAli Bahrami * exit: 174090a8d9eSAli Bahrami * On success, a new list node is created and the item is 175090a8d9eSAli Bahrami * added to the list. On failure, a fatal error is issued 176090a8d9eSAli Bahrami * and the process exits. 177090a8d9eSAli Bahrami */ 178090a8d9eSAli Bahrami static void 179090a8d9eSAli Bahrami pvs_aplist_append(APlist **lst, const void *item, const char *file) 180090a8d9eSAli Bahrami { 181090a8d9eSAli Bahrami if (aplist_append(lst, item, AL_CNT_GVER_DESC) == NULL) { 182090a8d9eSAli Bahrami int err = errno; 183090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file, 184090a8d9eSAli Bahrami strerror(err)); 185090a8d9eSAli Bahrami exit(1); 186090a8d9eSAli Bahrami } 187090a8d9eSAli Bahrami } 188090a8d9eSAli Bahrami 189090a8d9eSAli Bahrami /* 190090a8d9eSAli Bahrami * Add an entry to match_list for use by match(). This routine is for 191090a8d9eSAli Bahrami * use during getopt() processing. 192090a8d9eSAli Bahrami * 193090a8d9eSAli Bahrami * entry: 194090a8d9eSAli Bahrami * opt - One of 'N' or 'I', indicating the option 195090a8d9eSAli Bahrami * str - Value string corresponding to opt 196090a8d9eSAli Bahrami * 197090a8d9eSAli Bahrami * exit: 198090a8d9eSAli Bahrami * The new match record has been added. On error, a fatal 199090a8d9eSAli Bahrami * error is issued and and the process exits. 200090a8d9eSAli Bahrami */ 201090a8d9eSAli Bahrami static void 202090a8d9eSAli Bahrami add_match_record(int opt, const char *str) 203090a8d9eSAli Bahrami { 204090a8d9eSAli Bahrami /* 205090a8d9eSAli Bahrami * Macros for removing leading and trailing whitespace: 206090a8d9eSAli Bahrami * WS_SKIP - Advance _str without passing the NULL termination, 207090a8d9eSAli Bahrami * until the first character is not whitespace. 208090a8d9eSAli Bahrami * WS_SKIP_LIMIT - Advance _str without passing _limit, 209090a8d9eSAli Bahrami * until the first character is not whitespace. 210090a8d9eSAli Bahrami * WS_RSKIP_LIMIT - Move _tail back without passing _str, 211090a8d9eSAli Bahrami * until the character before it is not whitespace. 212090a8d9eSAli Bahrami * Write a NULL termination at that point. 213090a8d9eSAli Bahrami */ 214090a8d9eSAli Bahrami #define WS_SKIP(_str) for (; *(_str) && isspace(*(_str)); (_str)++) 215090a8d9eSAli Bahrami #define WS_SKIP_LIMIT(_str, _limit) \ 216090a8d9eSAli Bahrami while (((_str) < s2) && isspace(*(_str))) \ 217090a8d9eSAli Bahrami (_str)++ 218090a8d9eSAli Bahrami #define WS_RSKIP_LIMIT(_str, _tail) \ 219090a8d9eSAli Bahrami while (((_tail) > (_str)) && isspace(*((_tail) - 1))) \ 220090a8d9eSAli Bahrami (_tail)--; \ 221090a8d9eSAli Bahrami *(_tail) = '\0' 222090a8d9eSAli Bahrami 223090a8d9eSAli Bahrami 224090a8d9eSAli Bahrami match_rec_t *rec; 225090a8d9eSAli Bahrami char *lstr, *s1, *s2; 226090a8d9eSAli Bahrami 227090a8d9eSAli Bahrami rec = alist_append(&match_list, NULL, sizeof (match_rec_t), 228090a8d9eSAli Bahrami AL_CNT_MATCH_LIST); 229090a8d9eSAli Bahrami if (rec == NULL) { 230090a8d9eSAli Bahrami int err = errno; 231090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 232090a8d9eSAli Bahrami MSG_INTL(MSG_STR_MATCH_RECORD), strerror(err)); 233090a8d9eSAli Bahrami exit(1); 234090a8d9eSAli Bahrami } 235090a8d9eSAli Bahrami 236090a8d9eSAli Bahrami if (opt == 'N') { 237090a8d9eSAli Bahrami if ((lstr = strdup(str)) == NULL) { 238090a8d9eSAli Bahrami int err = errno; 239090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), 240090a8d9eSAli Bahrami cname, MSG_INTL(MSG_STR_MATCH_RECORD), 241090a8d9eSAli Bahrami strerror(err)); 242090a8d9eSAli Bahrami exit(1); 243090a8d9eSAli Bahrami } 244090a8d9eSAli Bahrami 245090a8d9eSAli Bahrami /* Strip leading/trailing whitespace */ 246090a8d9eSAli Bahrami s2 = lstr + strlen(lstr); 247090a8d9eSAli Bahrami WS_SKIP_LIMIT(lstr, s2); 248090a8d9eSAli Bahrami WS_RSKIP_LIMIT(lstr, s2); 249090a8d9eSAli Bahrami 250090a8d9eSAli Bahrami /* Assume this is a plain string */ 251090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_NAME; 252090a8d9eSAli Bahrami rec->value.name.version = lstr; 253090a8d9eSAli Bahrami 254090a8d9eSAli Bahrami /* 255090a8d9eSAli Bahrami * If s2 points at a closing paren, then this might 256090a8d9eSAli Bahrami * be a MATCH_OPT_NEED_VER case. Otherwise we're done. 257090a8d9eSAli Bahrami */ 258090a8d9eSAli Bahrami if ((s2 == lstr) || (*(s2 - 1) != ')')) 259090a8d9eSAli Bahrami return; 260090a8d9eSAli Bahrami 261090a8d9eSAli Bahrami /* We have a closing paren. Locate the opening one. */ 262090a8d9eSAli Bahrami for (s1 = lstr; *s1 && (*s1 != '('); s1++) 263090a8d9eSAli Bahrami ; 264090a8d9eSAli Bahrami if (*s1 != '(') 265090a8d9eSAli Bahrami return; 266090a8d9eSAli Bahrami 267090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_NEED_VER; 268090a8d9eSAli Bahrami rec->value.name.needobj = lstr; 269090a8d9eSAli Bahrami rec->value.name.version = s1 + 1; 270090a8d9eSAli Bahrami s2--; /* Points at closing paren */ 271090a8d9eSAli Bahrami 272090a8d9eSAli Bahrami /* Remove whitespace from head/tail of version */ 273090a8d9eSAli Bahrami WS_SKIP_LIMIT(rec->value.name.version, s2); 274090a8d9eSAli Bahrami WS_RSKIP_LIMIT(rec->value.name.version, s2); 275090a8d9eSAli Bahrami 276090a8d9eSAli Bahrami /* Terminate needobj, skipping trailing whitespace */ 277090a8d9eSAli Bahrami WS_RSKIP_LIMIT(rec->value.name.needobj, s1); 278090a8d9eSAli Bahrami 279090a8d9eSAli Bahrami return; 280090a8d9eSAli Bahrami } 281090a8d9eSAli Bahrami 282090a8d9eSAli Bahrami 283090a8d9eSAli Bahrami /* If we get here, we are looking at a -I index option */ 284090a8d9eSAli Bahrami rec->value.ndx.start = strtol(str, &s2, 10); 285090a8d9eSAli Bahrami /* Value must use some of the input, and be positive */ 286090a8d9eSAli Bahrami if ((str == s2) || (rec->value.ndx.start < 1)) 287090a8d9eSAli Bahrami goto syntax_error; 288090a8d9eSAli Bahrami str = s2; 289090a8d9eSAli Bahrami 290090a8d9eSAli Bahrami WS_SKIP(str); 291090a8d9eSAli Bahrami if (*str != ':') { 292090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_NDX; 293090a8d9eSAli Bahrami } else { 294090a8d9eSAli Bahrami str++; /* Skip the ':' */ 295090a8d9eSAli Bahrami rec->opt_type = MATCH_OPT_RANGE; 296090a8d9eSAli Bahrami WS_SKIP(str); 297090a8d9eSAli Bahrami if (*str == '\0') { 298090a8d9eSAli Bahrami rec->value.ndx.end = -1; /* Indicates "to end" */ 299090a8d9eSAli Bahrami } else { 300090a8d9eSAli Bahrami rec->value.ndx.end = strtol(str, &s2, 10); 301090a8d9eSAli Bahrami if ((str == s2) || (rec->value.ndx.end < 0)) 302090a8d9eSAli Bahrami goto syntax_error; 303090a8d9eSAli Bahrami str = s2; 304090a8d9eSAli Bahrami WS_SKIP(str); 305090a8d9eSAli Bahrami } 306090a8d9eSAli Bahrami } 307090a8d9eSAli Bahrami 308090a8d9eSAli Bahrami /* If we are successful, there is nothing left to parse */ 309090a8d9eSAli Bahrami if (*str == '\0') 310090a8d9eSAli Bahrami return; 311090a8d9eSAli Bahrami 312090a8d9eSAli Bahrami /* 313090a8d9eSAli Bahrami * If we get here, there is leftover input. Fall through 314090a8d9eSAli Bahrami * to issue a syntax error. 315090a8d9eSAli Bahrami */ 316090a8d9eSAli Bahrami syntax_error: 317090a8d9eSAli Bahrami (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 318090a8d9eSAli Bahrami exit(1); 319090a8d9eSAli Bahrami 320090a8d9eSAli Bahrami #undef WS_SKIP 321090a8d9eSAli Bahrami #undef WS_SKIP_LIMIT 322090a8d9eSAli Bahrami #undef WS_RSKIP_LIMIT 323090a8d9eSAli Bahrami } 324090a8d9eSAli Bahrami 325090a8d9eSAli Bahrami /* 326090a8d9eSAli Bahrami * Returns True (1) if the version with the given name or index should 327090a8d9eSAli Bahrami * be displayed, and False (0) if it should not be. 328090a8d9eSAli Bahrami * 329090a8d9eSAli Bahrami * entry: 330090a8d9eSAli Bahrami * needobj - NULL for VERDEF records, the name of the 331090a8d9eSAli Bahrami * needed object for VERNEED. 332090a8d9eSAli Bahrami * version - NULL, or needed version 333090a8d9eSAli Bahrami * ndx - Versym index of version under consideration, or a value less 334090a8d9eSAli Bahrami * than 1 to indicate that no valid index is given. 335090a8d9eSAli Bahrami * 336090a8d9eSAli Bahrami * exit: 337090a8d9eSAli Bahrami * True will be returned if the given name/index matches those given 338090a8d9eSAli Bahrami * by one of the -I or -N command line options, or if no such option 339090a8d9eSAli Bahrami * was used in the command invocation. 340090a8d9eSAli Bahrami */ 341090a8d9eSAli Bahrami int 342090a8d9eSAli Bahrami match(const char *needobj, const char *version, int ndx) 343090a8d9eSAli Bahrami { 344090a8d9eSAli Bahrami Aliste _idx; 345090a8d9eSAli Bahrami match_rec_t *rec; 346090a8d9eSAli Bahrami const char *str; 347090a8d9eSAli Bahrami 348090a8d9eSAli Bahrami /* If there is no match list, then we approve everything */ 349090a8d9eSAli Bahrami if (alist_nitems(match_list) == 0) 350090a8d9eSAli Bahrami return (1); 351090a8d9eSAli Bahrami 352090a8d9eSAli Bahrami /* Run through the match records and check for a hit */ 353090a8d9eSAli Bahrami for (ALIST_TRAVERSE(match_list, _idx, rec)) { 354090a8d9eSAli Bahrami switch (rec->opt_type) { 355090a8d9eSAli Bahrami case MATCH_OPT_NAME: 356090a8d9eSAli Bahrami if (needobj) 357090a8d9eSAli Bahrami str = needobj; 358090a8d9eSAli Bahrami else if (version) 359090a8d9eSAli Bahrami str = version; 360090a8d9eSAli Bahrami else 361090a8d9eSAli Bahrami break; 362090a8d9eSAli Bahrami if (strcmp(rec->value.name.version, str) == 0) 363090a8d9eSAli Bahrami return (1); 364090a8d9eSAli Bahrami break; 365090a8d9eSAli Bahrami case MATCH_OPT_NEED_VER: 366090a8d9eSAli Bahrami if (needobj && version && 367090a8d9eSAli Bahrami (strcmp(rec->value.name.needobj, needobj) == 0) && 368090a8d9eSAli Bahrami (strcmp(rec->value.name.version, version) == 0)) 369090a8d9eSAli Bahrami return (1); 370090a8d9eSAli Bahrami break; 371090a8d9eSAli Bahrami case MATCH_OPT_NDX: 372090a8d9eSAli Bahrami if ((ndx > 0) && (ndx == rec->value.ndx.start)) 373090a8d9eSAli Bahrami return (1); 374090a8d9eSAli Bahrami break; 375090a8d9eSAli Bahrami case MATCH_OPT_RANGE: 376090a8d9eSAli Bahrami /* 377090a8d9eSAli Bahrami * A range end value less than 0 means that any value 378090a8d9eSAli Bahrami * above the start is acceptible. 379090a8d9eSAli Bahrami */ 380090a8d9eSAli Bahrami if ((ndx > 0) && 381090a8d9eSAli Bahrami (ndx >= rec->value.ndx.start) && 382090a8d9eSAli Bahrami ((rec->value.ndx.end < 0) || 383090a8d9eSAli Bahrami (ndx <= rec->value.ndx.end))) 384090a8d9eSAli Bahrami return (1); 385090a8d9eSAli Bahrami break; 386090a8d9eSAli Bahrami } 387090a8d9eSAli Bahrami } 388090a8d9eSAli Bahrami 389090a8d9eSAli Bahrami /* Nothing matched */ 390090a8d9eSAli Bahrami return (0); 391090a8d9eSAli Bahrami } 392090a8d9eSAli Bahrami 393090a8d9eSAli Bahrami /* 394090a8d9eSAli Bahrami * List the symbols that belong to a specified version 395090a8d9eSAli Bahrami * 396090a8d9eSAli Bahrami * entry: 397090a8d9eSAli Bahrami * vsdata - VERSYM related data from the object 398090a8d9eSAli Bahrami * vd_ndx - The VERSYM index for symbols to display 399090a8d9eSAli Bahrami * vd_name - Version name 400090a8d9eSAli Bahrami * needobj - NULL for symbols corresponding to a VERDEF 401090a8d9eSAli Bahrami * record. Name of the needed object in the case 402090a8d9eSAli Bahrami * of a VERNEED record. 403090a8d9eSAli Bahrami * file - Object file 404090a8d9eSAli Bahrami */ 405090a8d9eSAli Bahrami static void 406090a8d9eSAli Bahrami gvers_syms(const Gver_sym_data *vsdata, GElf_Half vd_ndx, 407090a8d9eSAli Bahrami const char *vd_name, const char *needobj, const char *file) 408090a8d9eSAli Bahrami { 409090a8d9eSAli Bahrami GElf_Sym sym; 410090a8d9eSAli Bahrami int _symn; 411090a8d9eSAli Bahrami 412090a8d9eSAli Bahrami for (_symn = 0; _symn < vsdata->vsd_symn; _symn++) { 413090a8d9eSAli Bahrami size_t size = 0; 414090a8d9eSAli Bahrami const char *name; 415090a8d9eSAli Bahrami 416090a8d9eSAli Bahrami if (vsdata->vsd_vsp[_symn] != vd_ndx) 417090a8d9eSAli Bahrami continue; 418090a8d9eSAli Bahrami 419090a8d9eSAli Bahrami (void) gelf_getsym(vsdata->vsd_sym_data, _symn, &sym); 420090a8d9eSAli Bahrami name = demangle(vsdata->vsd_strs + sym.st_name); 421090a8d9eSAli Bahrami 422090a8d9eSAli Bahrami /* 423090a8d9eSAli Bahrami * Symbols that reference a VERDEF record 424090a8d9eSAli Bahrami * have some extra details to handle. 425090a8d9eSAli Bahrami */ 426090a8d9eSAli Bahrami if (needobj == NULL) { 427090a8d9eSAli Bahrami /* 428090a8d9eSAli Bahrami * For data symbols defined by this object, 429090a8d9eSAli Bahrami * determine the size. 430090a8d9eSAli Bahrami */ 431090a8d9eSAli Bahrami if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) || 432090a8d9eSAli Bahrami (GELF_ST_TYPE(sym.st_info) == STT_COMMON) || 433090a8d9eSAli Bahrami (GELF_ST_TYPE(sym.st_info) == STT_TLS)) 434090a8d9eSAli Bahrami size = (size_t)sym.st_size; 435090a8d9eSAli Bahrami 436090a8d9eSAli Bahrami /* 437090a8d9eSAli Bahrami * Only output the version symbol when the verbose 438090a8d9eSAli Bahrami * flag is used. 439090a8d9eSAli Bahrami */ 440090a8d9eSAli Bahrami if (!vflag && (sym.st_shndx == SHN_ABS) && 441090a8d9eSAli Bahrami (strcmp(name, vd_name) == 0)) 442090a8d9eSAli Bahrami continue; 443090a8d9eSAli Bahrami } 444090a8d9eSAli Bahrami 445090a8d9eSAli Bahrami if (oflag) { 446090a8d9eSAli Bahrami if (needobj == NULL) 447090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_OFIL), 448090a8d9eSAli Bahrami file, vd_name); 449090a8d9eSAli Bahrami else 450090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_NEED_OFIL), 451090a8d9eSAli Bahrami file, needobj, vd_name); 452090a8d9eSAli Bahrami 453090a8d9eSAli Bahrami if (size) 454090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ_OFLG), 455090a8d9eSAli Bahrami name, (ulong_t)size); 456090a8d9eSAli Bahrami else 457090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_OFLG), name); 458090a8d9eSAli Bahrami } else { 459090a8d9eSAli Bahrami if (size) 460090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM_SZ), name, 461090a8d9eSAli Bahrami (ulong_t)size); 462090a8d9eSAli Bahrami else 463090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SYM), name); 464090a8d9eSAli Bahrami } 465090a8d9eSAli Bahrami } 466090a8d9eSAli Bahrami } 467090a8d9eSAli Bahrami 4687c478bd9Sstevel@tonic-gate /* 4697c478bd9Sstevel@tonic-gate * Print any reduced symbols. The convention is that reduced symbols exist as 4707c478bd9Sstevel@tonic-gate * LOCL entries in the .symtab, between the FILE symbol for the output file and 4717c478bd9Sstevel@tonic-gate * the first FILE symbol for any input file used to build the output file. 4727c478bd9Sstevel@tonic-gate */ 4737c478bd9Sstevel@tonic-gate static void 4747c478bd9Sstevel@tonic-gate sym_local(Cache *cache, Cache *csym, const char *file) 4757c478bd9Sstevel@tonic-gate { 4767c478bd9Sstevel@tonic-gate int symn, _symn, found = 0; 4777c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 4787c478bd9Sstevel@tonic-gate GElf_Sym sym; 479090a8d9eSAli Bahrami char *strs; 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate (void) gelf_getshdr(csym->c_scn, &shdr); 4827c478bd9Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 4837c478bd9Sstevel@tonic-gate /* LINTED */ 4847c478bd9Sstevel@tonic-gate symn = shdr.sh_info; 4857c478bd9Sstevel@tonic-gate 4867c478bd9Sstevel@tonic-gate /* 4877c478bd9Sstevel@tonic-gate * Verify symtab[1] is the output file symbol. 4887c478bd9Sstevel@tonic-gate */ 4897c478bd9Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, 1, &sym); 4907c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_FILE) { 4917c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname, 4927c478bd9Sstevel@tonic-gate file); 4937c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE), 4947c478bd9Sstevel@tonic-gate csym->c_name); 4957c478bd9Sstevel@tonic-gate return; 4967c478bd9Sstevel@tonic-gate } 4977c478bd9Sstevel@tonic-gate 4987c478bd9Sstevel@tonic-gate /* 4997c478bd9Sstevel@tonic-gate * Scan the remaining symbols until the next file symbol is found. 5007c478bd9Sstevel@tonic-gate */ 5017c478bd9Sstevel@tonic-gate for (_symn = 2; _symn < symn; _symn++) { 5027c478bd9Sstevel@tonic-gate const char *name; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, _symn, &sym); 5057c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) 5067c478bd9Sstevel@tonic-gate continue; 5077c478bd9Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 5087c478bd9Sstevel@tonic-gate break; 5097c478bd9Sstevel@tonic-gate 5107c478bd9Sstevel@tonic-gate /* 5117c478bd9Sstevel@tonic-gate * Its possible that section symbols are followed immediately 5127c478bd9Sstevel@tonic-gate * by globals. This is the case if an object (filter) is 5137c478bd9Sstevel@tonic-gate * generated exclusively from mapfile symbol definitions. 5147c478bd9Sstevel@tonic-gate */ 5157c478bd9Sstevel@tonic-gate if (GELF_ST_BIND(sym.st_info) != STB_LOCAL) 5167c478bd9Sstevel@tonic-gate break; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate name = demangle(strs + sym.st_name); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate if (oflag) { 521090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_OFLG), 522090a8d9eSAli Bahrami file, name); 5237c478bd9Sstevel@tonic-gate } else { 5247c478bd9Sstevel@tonic-gate if (found == 0) { 5257c478bd9Sstevel@tonic-gate found = 1; 526090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LOCSYM_HDR)); 5277c478bd9Sstevel@tonic-gate } 528090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LOCSYM), name); 5297c478bd9Sstevel@tonic-gate } 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate /* 534090a8d9eSAli Bahrami * Print data from the files VERNEED section. 535090a8d9eSAli Bahrami * 536090a8d9eSAli Bahrami * If we have been asked to display symbols, then the 537090a8d9eSAli Bahrami * output format follows that used for verdef sections, 538090a8d9eSAli Bahrami * with each version displayed separately. For instance: 539090a8d9eSAli Bahrami * 540090a8d9eSAli Bahrami * libc.so.1 (SUNW_1.7): 541090a8d9eSAli Bahrami * sym1; 542090a8d9eSAli Bahrami * sym2; 543090a8d9eSAli Bahrami * libc.so.1 (SUNW_1.9): 544090a8d9eSAli Bahrami * sym3; 545090a8d9eSAli Bahrami * 546090a8d9eSAli Bahrami * If we are not displaying symbols, then a terse format 547090a8d9eSAli Bahrami * is used, which combines all the needed versions from 548090a8d9eSAli Bahrami * a given object into a single line. In this case, the 549090a8d9eSAli Bahrami * versions are shown whether or not they contribute symbols. 550090a8d9eSAli Bahrami * 551090a8d9eSAli Bahrami * libc.so.1 (SUNW_1.7, SUNW_1.9); 5527c478bd9Sstevel@tonic-gate */ 5537c478bd9Sstevel@tonic-gate static int 554090a8d9eSAli Bahrami gvers_need(Cache *cache, Cache *need, const Gver_sym_data *vsdata, 555090a8d9eSAli Bahrami const char *file) 5567c478bd9Sstevel@tonic-gate { 5577c478bd9Sstevel@tonic-gate unsigned int num, _num; 5587c478bd9Sstevel@tonic-gate char *strs; 5597c478bd9Sstevel@tonic-gate GElf_Verneed *vnd = need->c_data->d_buf; 5607c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 5617c478bd9Sstevel@tonic-gate int error = 0; 562090a8d9eSAli Bahrami int show = vflag || (vsdata == NULL) || !oflag; 563090a8d9eSAli Bahrami 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate (void) gelf_getshdr(need->c_scn, &shdr); 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Verify the version revision. We only check the first version 5697c478bd9Sstevel@tonic-gate * structure as it is assumed all other version structures in this 5707c478bd9Sstevel@tonic-gate * data section will be of the same revision. 5717c478bd9Sstevel@tonic-gate */ 5727c478bd9Sstevel@tonic-gate if (vnd->vn_version > VER_DEF_CURRENT) 5737c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 5747c478bd9Sstevel@tonic-gate vnd->vn_version, VER_DEF_CURRENT); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate /* 5777c478bd9Sstevel@tonic-gate * Get the data buffer for the associated string table. 5787c478bd9Sstevel@tonic-gate */ 5797c478bd9Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 5807c478bd9Sstevel@tonic-gate num = shdr.sh_info; 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 5837c478bd9Sstevel@tonic-gate vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 584090a8d9eSAli Bahrami GElf_Vernaux *vnap; 585090a8d9eSAli Bahrami Word ndx; 586d444b03eSAli Bahrami const char *needobj, *dep; 587d444b03eSAli Bahrami int started = 0, listcnt = 0; 5887c478bd9Sstevel@tonic-gate 589090a8d9eSAli Bahrami vnap = (GElf_Vernaux *) ((uintptr_t)vnd + vnd->vn_aux); 590090a8d9eSAli Bahrami 591090a8d9eSAli Bahrami /* Obtain the needed object file name */ 592090a8d9eSAli Bahrami needobj = (char *)(strs + vnd->vn_file); 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate error = 1; 5957c478bd9Sstevel@tonic-gate 596090a8d9eSAli Bahrami /* Process the versions needed from this object */ 597090a8d9eSAli Bahrami for (ndx = 0; ndx < vnd->vn_cnt; ndx++, 598090a8d9eSAli Bahrami vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) { 599090a8d9eSAli Bahrami Conv_ver_flags_buf_t ver_flags_buf; 6007c478bd9Sstevel@tonic-gate 6017c478bd9Sstevel@tonic-gate dep = (char *)(strs + vnap->vna_name); 6027c478bd9Sstevel@tonic-gate 603090a8d9eSAli Bahrami if (!match(needobj, dep, vnap->vna_other)) 604090a8d9eSAli Bahrami continue; 6057c478bd9Sstevel@tonic-gate 606090a8d9eSAli Bahrami if (show) { 607090a8d9eSAli Bahrami if ((started == 0) || (vsdata != NULL)) { 608090a8d9eSAli Bahrami /* 609090a8d9eSAli Bahrami * If one-line ouput is called for 610090a8d9eSAli Bahrami * display the filename being processed. 611090a8d9eSAli Bahrami */ 612090a8d9eSAli Bahrami if (oflag && show) 613090a8d9eSAli Bahrami (void) printf( 614090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_OFIL), 615090a8d9eSAli Bahrami file); 616090a8d9eSAli Bahrami 617090a8d9eSAli Bahrami (void) printf( 618090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_BEGIN), 619090a8d9eSAli Bahrami needobj); 620090a8d9eSAli Bahrami started = 1; 621090a8d9eSAli Bahrami } 622090a8d9eSAli Bahrami 623090a8d9eSAli Bahrami /* 624090a8d9eSAli Bahrami * If not showing symbols, only show INFO 625090a8d9eSAli Bahrami * versions in verbose mode. They don't 626090a8d9eSAli Bahrami * actually contribute to the version 627090a8d9eSAli Bahrami * interface as seen by rtld, so listing them 628090a8d9eSAli Bahrami * without qualification can be misleading. 629090a8d9eSAli Bahrami */ 630090a8d9eSAli Bahrami if (vflag || (vsdata != NULL) || 631090a8d9eSAli Bahrami (alist_nitems(match_list) != 0) || 632090a8d9eSAli Bahrami !(vnap->vna_flags & VER_FLG_INFO)) { 633d444b03eSAli Bahrami const char *fmt = (listcnt == 0) ? 634d444b03eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_FIRST) : 635d444b03eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_NEXT); 636d444b03eSAli Bahrami 637d444b03eSAli Bahrami if (vsdata == NULL) 638d444b03eSAli Bahrami listcnt++; 639090a8d9eSAli Bahrami (void) printf(fmt, dep); 640090a8d9eSAli Bahrami 641090a8d9eSAli Bahrami /* Show non-zero flags */ 642090a8d9eSAli Bahrami if (vflag && (vnap->vna_flags != 0)) 643090a8d9eSAli Bahrami (void) printf( 644090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_VER_FLG), 645090a8d9eSAli Bahrami conv_ver_flags( 646090a8d9eSAli Bahrami vnap->vna_flags, 647090a8d9eSAli Bahrami CONV_FMT_NOBKT, 648090a8d9eSAli Bahrami &ver_flags_buf)); 649090a8d9eSAli Bahrami } 650090a8d9eSAli Bahrami if (vsdata != NULL) 651090a8d9eSAli Bahrami (void) printf(oflag ? 652090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_END_SEM) : 653090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_END_COL)); 654090a8d9eSAli Bahrami } 655090a8d9eSAli Bahrami 656090a8d9eSAli Bahrami /* 657090a8d9eSAli Bahrami * If we are showing symbols, and vna_other is 658090a8d9eSAli Bahrami * non-zero, list them here. 659090a8d9eSAli Bahrami * 660090a8d9eSAli Bahrami * A value of 0 means that this object uses 661090a8d9eSAli Bahrami * traditional Solaris versioning rules, under 662090a8d9eSAli Bahrami * which VERSYM does not contain indexes to VERNEED 663090a8d9eSAli Bahrami * records. In this case, there is nothing to show. 664090a8d9eSAli Bahrami */ 665090a8d9eSAli Bahrami if (vsdata && (vnap->vna_other > 0)) 666090a8d9eSAli Bahrami gvers_syms(vsdata, vnap->vna_other, 667090a8d9eSAli Bahrami dep, needobj, file); 6687c478bd9Sstevel@tonic-gate } 669090a8d9eSAli Bahrami if (show && started && (vsdata == NULL)) 670090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_LIST_END_SEM)); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate return (error); 6737c478bd9Sstevel@tonic-gate } 6747c478bd9Sstevel@tonic-gate 6757c478bd9Sstevel@tonic-gate /* 676090a8d9eSAli Bahrami * Return a GVer_desc descriptor for the given version if one 677090a8d9eSAli Bahrami * exists. 678090a8d9eSAli Bahrami * 679090a8d9eSAli Bahrami * entry: 680090a8d9eSAli Bahrami * name - Version name 681090a8d9eSAli Bahrami * hash - ELF hash of name 682090a8d9eSAli Bahrami * lst - APlist of existing descriptors. 683090a8d9eSAli Bahrami * file - Object file containing the version 684090a8d9eSAli Bahrami * 685090a8d9eSAli Bahrami * exit: 686090a8d9eSAli Bahrami * Return the corresponding GVer_desc struct if it 687090a8d9eSAli Bahrami * exists, and NULL otherwise. 6887c478bd9Sstevel@tonic-gate */ 6897c478bd9Sstevel@tonic-gate static GVer_desc * 690090a8d9eSAli Bahrami gvers_find(const char *name, unsigned long hash, APlist *lst) 6917c478bd9Sstevel@tonic-gate { 692090a8d9eSAli Bahrami Aliste idx; 6937c478bd9Sstevel@tonic-gate GVer_desc *vdp; 6947c478bd9Sstevel@tonic-gate 695090a8d9eSAli Bahrami for (APLIST_TRAVERSE(lst, idx, vdp)) 696090a8d9eSAli Bahrami if ((vdp->vd_hash == hash) && 697090a8d9eSAli Bahrami (strcmp(vdp->vd_name, name) == 0)) 6987c478bd9Sstevel@tonic-gate return (vdp); 699090a8d9eSAli Bahrami 700090a8d9eSAli Bahrami return (NULL); 7017c478bd9Sstevel@tonic-gate } 7027c478bd9Sstevel@tonic-gate 703090a8d9eSAli Bahrami /* 704090a8d9eSAli Bahrami * Return a GVer_desc descriptor for the given version. 705090a8d9eSAli Bahrami * 706090a8d9eSAli Bahrami * entry: 707090a8d9eSAli Bahrami * name - Version name 708090a8d9eSAli Bahrami * hash - ELF hash of name 709090a8d9eSAli Bahrami * lst - List of existing descriptors. 710090a8d9eSAli Bahrami * file - Object file containing the version 711090a8d9eSAli Bahrami * 712090a8d9eSAli Bahrami * exit: 713090a8d9eSAli Bahrami * Return the corresponding GVer_desc struct. If the 714*6a6cfa5dSJason King * descriptor does not already exist, it is created. 715090a8d9eSAli Bahrami * On error, a fatal error is issued and the process exits. 716090a8d9eSAli Bahrami */ 7177c478bd9Sstevel@tonic-gate static GVer_desc * 718090a8d9eSAli Bahrami gvers_desc(const char *name, unsigned long hash, APlist **lst, const char *file) 7197c478bd9Sstevel@tonic-gate { 7207c478bd9Sstevel@tonic-gate GVer_desc *vdp; 7217c478bd9Sstevel@tonic-gate 722090a8d9eSAli Bahrami if ((vdp = gvers_find(name, hash, *lst)) == NULL) { 723090a8d9eSAli Bahrami if ((vdp = calloc(sizeof (GVer_desc), 1)) == NULL) { 7247c478bd9Sstevel@tonic-gate int err = errno; 7257c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 7267c478bd9Sstevel@tonic-gate file, strerror(err)); 7277c478bd9Sstevel@tonic-gate exit(1); 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate vdp->vd_name = name; 7317c478bd9Sstevel@tonic-gate vdp->vd_hash = hash; 7327c478bd9Sstevel@tonic-gate 733090a8d9eSAli Bahrami pvs_aplist_append(lst, vdp, file); 7347c478bd9Sstevel@tonic-gate } 7357c478bd9Sstevel@tonic-gate return (vdp); 7367c478bd9Sstevel@tonic-gate } 7377c478bd9Sstevel@tonic-gate 738090a8d9eSAli Bahrami /* 739090a8d9eSAli Bahrami * Insert a version dependency for the given GVer_desc descriptor. 740090a8d9eSAli Bahrami * 741090a8d9eSAli Bahrami * entry: 742090a8d9eSAli Bahrami * name - Dependency version name 743090a8d9eSAli Bahrami * hash - ELF hash of name 744090a8d9eSAli Bahrami * lst - List of existing descriptors. 745090a8d9eSAli Bahrami * vdp - Existing version descriptor to which the dependency 746090a8d9eSAli Bahrami * is to be added. 747090a8d9eSAli Bahrami * file - Object file containing the version 748090a8d9eSAli Bahrami * 749090a8d9eSAli Bahrami * exit: 750090a8d9eSAli Bahrami * A descriptor for the dependency version is looked up 751090a8d9eSAli Bahrami * (created if necessary), and then added to the dependency 752090a8d9eSAli Bahrami * list for vdp. Returns the dependency descriptor. On error, 753090a8d9eSAli Bahrami * a fatal error is issued and the process exits. 754090a8d9eSAli Bahrami */ 7557c478bd9Sstevel@tonic-gate static GVer_desc * 756090a8d9eSAli Bahrami gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, APlist **lst, 7577c478bd9Sstevel@tonic-gate const char *file) 7587c478bd9Sstevel@tonic-gate { 7597c478bd9Sstevel@tonic-gate GVer_desc *_vdp; 7607c478bd9Sstevel@tonic-gate 761090a8d9eSAli Bahrami _vdp = gvers_desc(name, hash, lst, file); 762090a8d9eSAli Bahrami pvs_aplist_append(&vdp->vd_deps, _vdp, file); 7637c478bd9Sstevel@tonic-gate return (vdp); 7647c478bd9Sstevel@tonic-gate } 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate static void 767090a8d9eSAli Bahrami gvers_derefer(GVer_desc *vdp, int weak) 7687c478bd9Sstevel@tonic-gate { 769090a8d9eSAli Bahrami Aliste idx; 770*6a6cfa5dSJason King GVer_desc *_vdp; 7717c478bd9Sstevel@tonic-gate 7727c478bd9Sstevel@tonic-gate /* 7737c478bd9Sstevel@tonic-gate * If the head of the list was a weak then we only clear out 7747c478bd9Sstevel@tonic-gate * weak dependencies, but if the head of the list was 'strong' 7757c478bd9Sstevel@tonic-gate * we clear the REFER bit on all dependencies. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak)) 7787c478bd9Sstevel@tonic-gate vdp->vd_flags &= ~FLG_VER_AVAIL; 7797c478bd9Sstevel@tonic-gate 780090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) 7817c478bd9Sstevel@tonic-gate gvers_derefer(_vdp, weak); 7827c478bd9Sstevel@tonic-gate } 7837c478bd9Sstevel@tonic-gate 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate static void 786090a8d9eSAli Bahrami recurse_syms(const Gver_sym_data *vsdata, GVer_desc *vdp, const char *file) 7877c478bd9Sstevel@tonic-gate { 788090a8d9eSAli Bahrami Aliste idx; 7897c478bd9Sstevel@tonic-gate GVer_desc *_vdp; 7907c478bd9Sstevel@tonic-gate 791090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx, _vdp)) { 7927c478bd9Sstevel@tonic-gate if (!oflag) 793090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNCO), _vdp->vd_name); 794090a8d9eSAli Bahrami gvers_syms(vsdata, _vdp->vd_ndx, _vdp->vd_name, NULL, file); 795090a8d9eSAli Bahrami if (aplist_nitems(_vdp->vd_deps) != 0) 796090a8d9eSAli Bahrami recurse_syms(vsdata, _vdp, file); 7977c478bd9Sstevel@tonic-gate } 7987c478bd9Sstevel@tonic-gate } 7997c478bd9Sstevel@tonic-gate 8007c478bd9Sstevel@tonic-gate 8017c478bd9Sstevel@tonic-gate /* 8027c478bd9Sstevel@tonic-gate * Print the files version definition sections. 8037c478bd9Sstevel@tonic-gate */ 8047c478bd9Sstevel@tonic-gate static int 805090a8d9eSAli Bahrami gvers_def(Cache *cache, Cache *def, const Gver_sym_data *vsdata, 806090a8d9eSAli Bahrami const char *file) 8077c478bd9Sstevel@tonic-gate { 8087c478bd9Sstevel@tonic-gate unsigned int num, _num; 8097c478bd9Sstevel@tonic-gate char *strs; 8107c478bd9Sstevel@tonic-gate GElf_Verdef *vdf = def->c_data->d_buf; 8117c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 812090a8d9eSAli Bahrami GVer_desc *vdp, *bvdp = NULL; 813090a8d9eSAli Bahrami Aliste idx1; 814090a8d9eSAli Bahrami APlist *verdefs = NULL; 8157c478bd9Sstevel@tonic-gate int error = 0; 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * Verify the version revision. We only check the first version 8197c478bd9Sstevel@tonic-gate * structure as it is assumed all other version structures in this 8207c478bd9Sstevel@tonic-gate * data section will be of the same revision. 8217c478bd9Sstevel@tonic-gate */ 8227c478bd9Sstevel@tonic-gate if (vdf->vd_version > VER_DEF_CURRENT) { 8237c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 8247c478bd9Sstevel@tonic-gate vdf->vd_version, VER_DEF_CURRENT); 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate /* 8287c478bd9Sstevel@tonic-gate * Get the data buffer for the associated string table. 8297c478bd9Sstevel@tonic-gate */ 8307c478bd9Sstevel@tonic-gate (void) gelf_getshdr(def->c_scn, &shdr); 8317c478bd9Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 8327c478bd9Sstevel@tonic-gate num = shdr.sh_info; 8337c478bd9Sstevel@tonic-gate 8347c478bd9Sstevel@tonic-gate /* 8357c478bd9Sstevel@tonic-gate * Process the version definitions placing each on a version dependency 8367c478bd9Sstevel@tonic-gate * list. 8377c478bd9Sstevel@tonic-gate */ 8387c478bd9Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 8397c478bd9Sstevel@tonic-gate vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 8407c478bd9Sstevel@tonic-gate GElf_Half cnt = vdf->vd_cnt; 8417c478bd9Sstevel@tonic-gate GElf_Half ndx = vdf->vd_ndx; 842090a8d9eSAli Bahrami GElf_Verdaux *vdap; 8437c478bd9Sstevel@tonic-gate const char *_name; 8447c478bd9Sstevel@tonic-gate 845090a8d9eSAli Bahrami vdap = (GElf_Verdaux *)((uintptr_t)vdf + vdf->vd_aux); 846090a8d9eSAli Bahrami 8477c478bd9Sstevel@tonic-gate /* 8487c478bd9Sstevel@tonic-gate * Determine the version name and any dependencies. 8497c478bd9Sstevel@tonic-gate */ 8507c478bd9Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 8517c478bd9Sstevel@tonic-gate 852090a8d9eSAli Bahrami vdp = gvers_desc(_name, elf_hash(_name), &verdefs, file); 8537c478bd9Sstevel@tonic-gate vdp->vd_ndx = ndx; 8547c478bd9Sstevel@tonic-gate vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL; 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next); 8577c478bd9Sstevel@tonic-gate for (cnt--; cnt; cnt--, 8587c478bd9Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) { 8597c478bd9Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 8607c478bd9Sstevel@tonic-gate if (gvers_depend(_name, elf_hash(_name), vdp, 861090a8d9eSAli Bahrami &verdefs, file) == NULL) 8627c478bd9Sstevel@tonic-gate return (0); 8637c478bd9Sstevel@tonic-gate } 8647c478bd9Sstevel@tonic-gate 8657c478bd9Sstevel@tonic-gate /* 8667c478bd9Sstevel@tonic-gate * Remember the base version for possible later use. 8677c478bd9Sstevel@tonic-gate */ 8687c478bd9Sstevel@tonic-gate if (ndx == VER_NDX_GLOBAL) 8697c478bd9Sstevel@tonic-gate bvdp = vdp; 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * Normalize the dependency list if required. 8747c478bd9Sstevel@tonic-gate */ 8757c478bd9Sstevel@tonic-gate if (nflag) { 876090a8d9eSAli Bahrami for (APLIST_TRAVERSE(verdefs, idx1, vdp)) { 877090a8d9eSAli Bahrami Aliste idx2; 878*6a6cfa5dSJason King GVer_desc *_vdp; 8797c478bd9Sstevel@tonic-gate int type = vdp->vd_flags & VER_FLG_WEAK; 8807c478bd9Sstevel@tonic-gate 881090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) 8827c478bd9Sstevel@tonic-gate gvers_derefer(_vdp, type); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* 8867c478bd9Sstevel@tonic-gate * Always dereference the base version. 8877c478bd9Sstevel@tonic-gate */ 8887c478bd9Sstevel@tonic-gate if (bvdp) 8897c478bd9Sstevel@tonic-gate bvdp->vd_flags &= ~FLG_VER_AVAIL; 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate 8937c478bd9Sstevel@tonic-gate /* 8947c478bd9Sstevel@tonic-gate * Traverse the dependency list and print out the appropriate 8957c478bd9Sstevel@tonic-gate * information. 8967c478bd9Sstevel@tonic-gate */ 897090a8d9eSAli Bahrami for (APLIST_TRAVERSE(verdefs, idx1, vdp)) { 898090a8d9eSAli Bahrami Aliste idx2; 899*6a6cfa5dSJason King GVer_desc *_vdp; 9007c478bd9Sstevel@tonic-gate int count; 9017c478bd9Sstevel@tonic-gate 902090a8d9eSAli Bahrami if (!match(NULL, vdp->vd_name, vdp->vd_ndx)) 9037c478bd9Sstevel@tonic-gate continue; 904090a8d9eSAli Bahrami if ((alist_nitems(match_list) == 0) && 905090a8d9eSAli Bahrami !(vdp->vd_flags & FLG_VER_AVAIL)) 9067c478bd9Sstevel@tonic-gate continue; 9077c478bd9Sstevel@tonic-gate 9087c478bd9Sstevel@tonic-gate error = 1; 9097c478bd9Sstevel@tonic-gate 9107c478bd9Sstevel@tonic-gate if (vflag) { 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate * If the verbose flag is set determine if this version 9137c478bd9Sstevel@tonic-gate * has a `weak' attribute, and print any version 9147c478bd9Sstevel@tonic-gate * dependencies this version inherits. 9157c478bd9Sstevel@tonic-gate */ 9167c478bd9Sstevel@tonic-gate if (oflag) 917090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_OFIL), file); 918090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_VER_NAME), vdp->vd_name); 919090a8d9eSAli Bahrami if ((vdp->vd_flags & MSK_VER_USER) != 0) { 920090a8d9eSAli Bahrami Conv_ver_flags_buf_t ver_flags_buf; 921090a8d9eSAli Bahrami 922090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_VER_FLG), 923090a8d9eSAli Bahrami conv_ver_flags( 924090a8d9eSAli Bahrami vdp->vd_flags & MSK_VER_USER, 925090a8d9eSAli Bahrami CONV_FMT_NOBKT, &ver_flags_buf)); 926090a8d9eSAli Bahrami } 9277c478bd9Sstevel@tonic-gate 9287c478bd9Sstevel@tonic-gate count = 1; 929090a8d9eSAli Bahrami for (APLIST_TRAVERSE(vdp->vd_deps, idx2, _vdp)) { 9307c478bd9Sstevel@tonic-gate const char *_name = _vdp->vd_name; 9317c478bd9Sstevel@tonic-gate 9327c478bd9Sstevel@tonic-gate if (count++ == 1) { 933090a8d9eSAli Bahrami 9347c478bd9Sstevel@tonic-gate if (oflag) 935090a8d9eSAli Bahrami (void) printf( 936090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_IN_OFLG), 937090a8d9eSAli Bahrami _name); 9387c478bd9Sstevel@tonic-gate else if (vdp->vd_flags & VER_FLG_WEAK) 939090a8d9eSAli Bahrami (void) printf( 940090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_IN_WEAK), 941090a8d9eSAli Bahrami _name); 9427c478bd9Sstevel@tonic-gate else 943090a8d9eSAli Bahrami (void) printf( 944090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_IN), 9457c478bd9Sstevel@tonic-gate _name); 9467c478bd9Sstevel@tonic-gate } else 947090a8d9eSAli Bahrami (void) printf( 948090a8d9eSAli Bahrami MSG_ORIG(MSG_FMT_LIST_NEXT), _name); 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate 9517c478bd9Sstevel@tonic-gate if (count != 1) 952090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_IN_END)); 9537c478bd9Sstevel@tonic-gate 954090a8d9eSAli Bahrami if (vsdata && !oflag) 955090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_COL_NL)); 9567c478bd9Sstevel@tonic-gate else 957090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_SEM_NL)); 9587c478bd9Sstevel@tonic-gate } else { 959090a8d9eSAli Bahrami if (vsdata && !oflag) 960090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNCO), 961090a8d9eSAli Bahrami vdp->vd_name); 962090a8d9eSAli Bahrami else if (!vsdata) { 9637c478bd9Sstevel@tonic-gate if (oflag) 964090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_OFIL), 965090a8d9eSAli Bahrami file); 966090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNSE), 967090a8d9eSAli Bahrami vdp->vd_name); 9687c478bd9Sstevel@tonic-gate } 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 971090a8d9eSAli Bahrami /* If we are not printing symbols, we're done */ 972090a8d9eSAli Bahrami if (vsdata == NULL) 9737c478bd9Sstevel@tonic-gate continue; 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate /* 976090a8d9eSAli Bahrami * If a specific version to match has been specified then 977090a8d9eSAli Bahrami * display any of its own symbols plus any inherited from 978090a8d9eSAli Bahrami * other versions. Otherwise simply print out the symbols 979090a8d9eSAli Bahrami * for this version. 9807c478bd9Sstevel@tonic-gate */ 981090a8d9eSAli Bahrami gvers_syms(vsdata, vdp->vd_ndx, vdp->vd_name, NULL, file); 982090a8d9eSAli Bahrami if (alist_nitems(match_list) != 0) { 983090a8d9eSAli Bahrami recurse_syms(vsdata, vdp, file); 9847c478bd9Sstevel@tonic-gate 9857c478bd9Sstevel@tonic-gate /* 986090a8d9eSAli Bahrami * If the verbose flag is set, and this is not 987090a8d9eSAli Bahrami * the base version, then add the base version as a 988090a8d9eSAli Bahrami * dependency. 9897c478bd9Sstevel@tonic-gate */ 990090a8d9eSAli Bahrami if (vflag && bvdp && 991090a8d9eSAli Bahrami !match(NULL, bvdp->vd_name, bvdp->vd_ndx)) { 9927c478bd9Sstevel@tonic-gate if (!oflag) 993090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_TNCO), 994090a8d9eSAli Bahrami bvdp->vd_name); 995090a8d9eSAli Bahrami gvers_syms(vsdata, bvdp->vd_ndx, 996090a8d9eSAli Bahrami bvdp->vd_name, NULL, file); 9977c478bd9Sstevel@tonic-gate } 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate return (error); 10017c478bd9Sstevel@tonic-gate } 10027c478bd9Sstevel@tonic-gate 10037c478bd9Sstevel@tonic-gate int 10047c478bd9Sstevel@tonic-gate main(int argc, char **argv, char **envp) 10057c478bd9Sstevel@tonic-gate { 10067c478bd9Sstevel@tonic-gate GElf_Shdr shdr; 10077c478bd9Sstevel@tonic-gate Elf *elf; 10087c478bd9Sstevel@tonic-gate Elf_Scn *scn; 10097c478bd9Sstevel@tonic-gate Elf_Data *data; 1010*6a6cfa5dSJason King GElf_Ehdr ehdr; 10117c478bd9Sstevel@tonic-gate int nfile, var; 10127c478bd9Sstevel@tonic-gate char *names; 10137c478bd9Sstevel@tonic-gate Cache *cache, *_cache; 10147c478bd9Sstevel@tonic-gate Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc; 10157c478bd9Sstevel@tonic-gate int error = 0; 1016*6a6cfa5dSJason King Gver_sym_data vsdata_s; 1017090a8d9eSAli Bahrami const Gver_sym_data *vsdata = NULL; 10187c478bd9Sstevel@tonic-gate 10197c478bd9Sstevel@tonic-gate /* 10207c478bd9Sstevel@tonic-gate * Check for a binary that better fits this architecture. 10217c478bd9Sstevel@tonic-gate */ 10227010c12aSrie (void) conv_check_native(argv, envp); 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate /* 10257c478bd9Sstevel@tonic-gate * Establish locale. 10267c478bd9Sstevel@tonic-gate */ 10277c478bd9Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 10287c478bd9Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 10297c478bd9Sstevel@tonic-gate 10307c478bd9Sstevel@tonic-gate cname = argv[0]; 10317c478bd9Sstevel@tonic-gate Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0; 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate opterr = 0; 1034090a8d9eSAli Bahrami while ((var = getopt(argc, argv, MSG_ORIG(MSG_STR_OPTIONS))) != EOF) { 10357c478bd9Sstevel@tonic-gate switch (var) { 10367c478bd9Sstevel@tonic-gate case 'C': 10377c478bd9Sstevel@tonic-gate Cflag = USR_DEFINED; 10387c478bd9Sstevel@tonic-gate break; 10397c478bd9Sstevel@tonic-gate case 'd': 10407c478bd9Sstevel@tonic-gate dflag = USR_DEFINED; 10417c478bd9Sstevel@tonic-gate break; 10427c478bd9Sstevel@tonic-gate case 'l': 1043090a8d9eSAli Bahrami lflag = sflag = USR_DEFINED; 10447c478bd9Sstevel@tonic-gate break; 10457c478bd9Sstevel@tonic-gate case 'n': 10467c478bd9Sstevel@tonic-gate nflag = USR_DEFINED; 10477c478bd9Sstevel@tonic-gate break; 10487c478bd9Sstevel@tonic-gate case 'o': 10497c478bd9Sstevel@tonic-gate oflag = USR_DEFINED; 10507c478bd9Sstevel@tonic-gate break; 10517c478bd9Sstevel@tonic-gate case 'r': 10527c478bd9Sstevel@tonic-gate rflag = USR_DEFINED; 10537c478bd9Sstevel@tonic-gate break; 10547c478bd9Sstevel@tonic-gate case 's': 10557c478bd9Sstevel@tonic-gate sflag = USR_DEFINED; 10567c478bd9Sstevel@tonic-gate break; 10577c478bd9Sstevel@tonic-gate case 'v': 10587c478bd9Sstevel@tonic-gate vflag = USR_DEFINED; 10597c478bd9Sstevel@tonic-gate break; 1060090a8d9eSAli Bahrami case 'I': 10617c478bd9Sstevel@tonic-gate case 'N': 1062090a8d9eSAli Bahrami add_match_record(var, optarg); 10637c478bd9Sstevel@tonic-gate break; 10647c478bd9Sstevel@tonic-gate case '?': 10657c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 10667c478bd9Sstevel@tonic-gate cname); 10677c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL)); 10687c478bd9Sstevel@tonic-gate exit(1); 10697c478bd9Sstevel@tonic-gate default: 10707c478bd9Sstevel@tonic-gate break; 10717c478bd9Sstevel@tonic-gate } 10727c478bd9Sstevel@tonic-gate } 10737c478bd9Sstevel@tonic-gate 10747c478bd9Sstevel@tonic-gate /* 10757c478bd9Sstevel@tonic-gate * No files specified on the command line? 10767c478bd9Sstevel@tonic-gate */ 10777c478bd9Sstevel@tonic-gate if ((nfile = argc - optind) == 0) { 10787c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 10797c478bd9Sstevel@tonic-gate exit(1); 10807c478bd9Sstevel@tonic-gate } 10817c478bd9Sstevel@tonic-gate 10827c478bd9Sstevel@tonic-gate /* 10837c478bd9Sstevel@tonic-gate * By default print both version definitions and needed dependencies. 10847c478bd9Sstevel@tonic-gate */ 1085090a8d9eSAli Bahrami if ((dflag == 0) && (rflag == 0) && (lflag == 0)) 10867c478bd9Sstevel@tonic-gate dflag = rflag = DEF_DEFINED; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* 10897c478bd9Sstevel@tonic-gate * Open the input file and initialize the elf interface. 10907c478bd9Sstevel@tonic-gate */ 10917c478bd9Sstevel@tonic-gate for (; optind < argc; optind++) { 10927c478bd9Sstevel@tonic-gate int derror = 0, nerror = 0, err; 10937c478bd9Sstevel@tonic-gate const char *file = argv[optind]; 1094a0563a48SRichard Lowe size_t shnum = 0; 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate if ((var = open(file, O_RDONLY)) == -1) { 10977c478bd9Sstevel@tonic-gate err = errno; 10987c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 10997c478bd9Sstevel@tonic-gate cname, file, strerror(err)); 11007c478bd9Sstevel@tonic-gate error = 1; 11017c478bd9Sstevel@tonic-gate continue; 11027c478bd9Sstevel@tonic-gate } 11037c478bd9Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 11047c478bd9Sstevel@tonic-gate if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) { 11057c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname, 11067c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11077c478bd9Sstevel@tonic-gate error = 1; 11087c478bd9Sstevel@tonic-gate (void) close(var); 11097c478bd9Sstevel@tonic-gate continue; 11107c478bd9Sstevel@tonic-gate } 11117c478bd9Sstevel@tonic-gate if (elf_kind(elf) != ELF_K_ELF) { 11127c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname, 11137c478bd9Sstevel@tonic-gate file); 11147c478bd9Sstevel@tonic-gate error = 1; 11157c478bd9Sstevel@tonic-gate (void) close(var); 11167c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11177c478bd9Sstevel@tonic-gate continue; 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) { 11207c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname, 11217c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11227c478bd9Sstevel@tonic-gate error = 1; 11237c478bd9Sstevel@tonic-gate (void) close(var); 11247c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11257c478bd9Sstevel@tonic-gate continue; 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required 11307c478bd9Sstevel@tonic-gate * section name strings. 11317c478bd9Sstevel@tonic-gate */ 11327c478bd9Sstevel@tonic-gate if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) { 11337c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname, 11347c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11357c478bd9Sstevel@tonic-gate error = 1; 11367c478bd9Sstevel@tonic-gate (void) close(var); 11377c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11387c478bd9Sstevel@tonic-gate continue; 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate if ((data = elf_getdata(scn, NULL)) == NULL) { 11417c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname, 11427c478bd9Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 11437c478bd9Sstevel@tonic-gate error = 1; 11447c478bd9Sstevel@tonic-gate (void) close(var); 11457c478bd9Sstevel@tonic-gate (void) elf_end(elf); 11467c478bd9Sstevel@tonic-gate continue; 11477c478bd9Sstevel@tonic-gate } 11487c478bd9Sstevel@tonic-gate names = data->d_buf; 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate /* 11517c478bd9Sstevel@tonic-gate * Fill in the cache descriptor with information for each 11527c478bd9Sstevel@tonic-gate * section we might need. We probably only need to save 11537c478bd9Sstevel@tonic-gate * read-only allocable sections as this is where the version 11547c478bd9Sstevel@tonic-gate * structures and their associated symbols and strings live. 11557c478bd9Sstevel@tonic-gate * However, God knows what someone can do with a mapfile, and 11567c478bd9Sstevel@tonic-gate * as elf_begin has already gone through all the overhead we 11577c478bd9Sstevel@tonic-gate * might as well set up the cache for every section. 11587c478bd9Sstevel@tonic-gate */ 1159a0563a48SRichard Lowe if (elf_getshdrnum(elf, &shnum) == -1) { 1160a0563a48SRichard Lowe (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSHDRNUM), 1161a0563a48SRichard Lowe cname, file, elf_errmsg(elf_errno())); 1162a0563a48SRichard Lowe exit(1); 1163a0563a48SRichard Lowe } 1164a0563a48SRichard Lowe 1165a0563a48SRichard Lowe if ((cache = calloc(shnum, sizeof (Cache))) == NULL) { 11667c478bd9Sstevel@tonic-gate int err = errno; 11677c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 11687c478bd9Sstevel@tonic-gate file, strerror(err)); 11697c478bd9Sstevel@tonic-gate exit(1); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 1172090a8d9eSAli Bahrami _cache_def = _cache_need = _cache_sym = _cache_loc = NULL; 11737c478bd9Sstevel@tonic-gate _cache = cache; 11747c478bd9Sstevel@tonic-gate _cache++; 11757c478bd9Sstevel@tonic-gate for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) { 11767c478bd9Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL) { 11777c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11787c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETSHDR), cname, file, 11797c478bd9Sstevel@tonic-gate elf_errmsg(elf_errno())); 11807c478bd9Sstevel@tonic-gate error = 1; 11817c478bd9Sstevel@tonic-gate continue; 11827c478bd9Sstevel@tonic-gate } 11837c478bd9Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == 11847c478bd9Sstevel@tonic-gate NULL) { 11857c478bd9Sstevel@tonic-gate (void) fprintf(stderr, 11867c478bd9Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETDATA), cname, file, 11877c478bd9Sstevel@tonic-gate elf_errmsg(elf_errno())); 11887c478bd9Sstevel@tonic-gate error = 1; 11897c478bd9Sstevel@tonic-gate continue; 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate _cache->c_scn = scn; 11927c478bd9Sstevel@tonic-gate _cache->c_name = names + shdr.sh_name; 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate /* 11957c478bd9Sstevel@tonic-gate * Remember the version sections and symbol table. 11967c478bd9Sstevel@tonic-gate */ 11979039eeafSab switch (shdr.sh_type) { 11989039eeafSab case SHT_SUNW_verdef: 11999039eeafSab if (dflag) 12009039eeafSab _cache_def = _cache; 12019039eeafSab break; 12029039eeafSab case SHT_SUNW_verneed: 12039039eeafSab if (rflag) 12049039eeafSab _cache_need = _cache; 12059039eeafSab break; 12069039eeafSab case SHT_SUNW_versym: 12079039eeafSab if (sflag) 12089039eeafSab _cache_sym = _cache; 12099039eeafSab break; 12109039eeafSab case SHT_SYMTAB: 12119039eeafSab if (lflag) 12129039eeafSab _cache_loc = _cache; 12139039eeafSab break; 12149039eeafSab } 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate /* 12187c478bd9Sstevel@tonic-gate * Before printing anything out determine if any warnings are 12197c478bd9Sstevel@tonic-gate * necessary. 12207c478bd9Sstevel@tonic-gate */ 1221090a8d9eSAli Bahrami if (lflag && (_cache_loc == NULL)) { 12227c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), 12237c478bd9Sstevel@tonic-gate cname, file); 12247c478bd9Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB)); 12257c478bd9Sstevel@tonic-gate } 12267c478bd9Sstevel@tonic-gate 12277c478bd9Sstevel@tonic-gate /* 12287c478bd9Sstevel@tonic-gate * If there is more than one input file, and we're not printing 12297c478bd9Sstevel@tonic-gate * one-line output, display the filename being processed. 12307c478bd9Sstevel@tonic-gate */ 12317c478bd9Sstevel@tonic-gate if ((nfile > 1) && !oflag) 1232090a8d9eSAli Bahrami (void) printf(MSG_ORIG(MSG_FMT_FILE), file); 1233090a8d9eSAli Bahrami 1234090a8d9eSAli Bahrami /* 1235090a8d9eSAli Bahrami * If we're printing symbols, then collect the data 1236090a8d9eSAli Bahrami * necessary to do that. 1237090a8d9eSAli Bahrami */ 1238090a8d9eSAli Bahrami if (_cache_sym != NULL) { 1239090a8d9eSAli Bahrami vsdata = &vsdata_s; 1240090a8d9eSAli Bahrami (void) gelf_getshdr(_cache_sym->c_scn, &shdr); 1241090a8d9eSAli Bahrami vsdata_s.vsd_vsp = 1242090a8d9eSAli Bahrami (GElf_Versym *)_cache_sym->c_data->d_buf; 1243090a8d9eSAli Bahrami vsdata_s.vsd_sym_data = cache[shdr.sh_link].c_data; 1244090a8d9eSAli Bahrami (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr); 1245090a8d9eSAli Bahrami vsdata_s.vsd_symn = shdr.sh_size / shdr.sh_entsize; 1246090a8d9eSAli Bahrami vsdata_s.vsd_strs = 1247090a8d9eSAli Bahrami (const char *)cache[shdr.sh_link].c_data->d_buf; 1248090a8d9eSAli Bahrami } 1249090a8d9eSAli Bahrami 12507c478bd9Sstevel@tonic-gate 12517c478bd9Sstevel@tonic-gate /* 12527c478bd9Sstevel@tonic-gate * Print the files version needed sections. 12537c478bd9Sstevel@tonic-gate */ 12547c478bd9Sstevel@tonic-gate if (_cache_need) 1255090a8d9eSAli Bahrami nerror = gvers_need(cache, _cache_need, vsdata, file); 12567c478bd9Sstevel@tonic-gate 12577c478bd9Sstevel@tonic-gate /* 12587c478bd9Sstevel@tonic-gate * Print the files version definition sections. 12597c478bd9Sstevel@tonic-gate */ 12607c478bd9Sstevel@tonic-gate if (_cache_def) 1261090a8d9eSAli Bahrami derror = gvers_def(cache, _cache_def, vsdata, file); 12627c478bd9Sstevel@tonic-gate 12637c478bd9Sstevel@tonic-gate /* 12647c478bd9Sstevel@tonic-gate * Print any local symbol reductions. 12657c478bd9Sstevel@tonic-gate */ 12667c478bd9Sstevel@tonic-gate if (_cache_loc) 12677c478bd9Sstevel@tonic-gate sym_local(cache, _cache_loc, file); 12687c478bd9Sstevel@tonic-gate 12697c478bd9Sstevel@tonic-gate /* 12707c478bd9Sstevel@tonic-gate * Determine the error return. There are three conditions that 12717c478bd9Sstevel@tonic-gate * may produce an error (a non-zero return): 12727c478bd9Sstevel@tonic-gate * 12737c478bd9Sstevel@tonic-gate * o if the user specified -d and no version definitions 12747c478bd9Sstevel@tonic-gate * were found. 12757c478bd9Sstevel@tonic-gate * 12767c478bd9Sstevel@tonic-gate * o if the user specified -r and no version requirements 12777c478bd9Sstevel@tonic-gate * were found. 12787c478bd9Sstevel@tonic-gate * 12797c478bd9Sstevel@tonic-gate * o if the user specified neither -d or -r, (thus both are 12807c478bd9Sstevel@tonic-gate * enabled by default), and no version definitions or 12817c478bd9Sstevel@tonic-gate * version dependencies were found. 12827c478bd9Sstevel@tonic-gate */ 12837c478bd9Sstevel@tonic-gate if (((dflag == USR_DEFINED) && (derror == 0)) || 12847c478bd9Sstevel@tonic-gate ((rflag == USR_DEFINED) && (nerror == 0)) || 12857c478bd9Sstevel@tonic-gate (rflag && dflag && (derror == 0) && (nerror == 0))) 12867c478bd9Sstevel@tonic-gate error = 1; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate (void) close(var); 12897c478bd9Sstevel@tonic-gate (void) elf_end(elf); 12907c478bd9Sstevel@tonic-gate free(cache); 12917c478bd9Sstevel@tonic-gate } 12927c478bd9Sstevel@tonic-gate return (error); 12937c478bd9Sstevel@tonic-gate } 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate const char * 12967c478bd9Sstevel@tonic-gate _pvs_msg(Msg mid) 12977c478bd9Sstevel@tonic-gate { 12987c478bd9Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 12997c478bd9Sstevel@tonic-gate } 1300