1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * Analyze the versioning information within a file. 31*0Sstevel@tonic-gate * 32*0Sstevel@tonic-gate * -C demangle C++ symbol names. 33*0Sstevel@tonic-gate * 34*0Sstevel@tonic-gate * -d dump version definitions. 35*0Sstevel@tonic-gate * 36*0Sstevel@tonic-gate * -l print reduced (local) symbols. 37*0Sstevel@tonic-gate * 38*0Sstevel@tonic-gate * -n normalize any version definitions. 39*0Sstevel@tonic-gate * 40*0Sstevel@tonic-gate * -o dump output in one-line fashion (more suitable for grep'ing 41*0Sstevel@tonic-gate * and diff'ing). 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * -r dump the version requirements on library dependencies 44*0Sstevel@tonic-gate * 45*0Sstevel@tonic-gate * -s display the symbols associated with each version definition. 46*0Sstevel@tonic-gate * 47*0Sstevel@tonic-gate * -v verbose output. With the -r and -d options any WEAK attribute 48*0Sstevel@tonic-gate * is displayed. With the -d option, any version inheritance, 49*0Sstevel@tonic-gate * and the base version are displayed. With the -s option the 50*0Sstevel@tonic-gate * version symbol is displayed. 51*0Sstevel@tonic-gate * 52*0Sstevel@tonic-gate * -N name only print the specifed `name'. 53*0Sstevel@tonic-gate */ 54*0Sstevel@tonic-gate #include <fcntl.h> 55*0Sstevel@tonic-gate #include <stdio.h> 56*0Sstevel@tonic-gate #include <libelf.h> 57*0Sstevel@tonic-gate #include <link.h> 58*0Sstevel@tonic-gate #include <stdlib.h> 59*0Sstevel@tonic-gate #include <string.h> 60*0Sstevel@tonic-gate #include <unistd.h> 61*0Sstevel@tonic-gate #include <locale.h> 62*0Sstevel@tonic-gate #include <errno.h> 63*0Sstevel@tonic-gate #include <sys/varargs.h> 64*0Sstevel@tonic-gate #include "sgs.h" 65*0Sstevel@tonic-gate #include "conv.h" 66*0Sstevel@tonic-gate #include "debug.h" 67*0Sstevel@tonic-gate #include "gelf.h" 68*0Sstevel@tonic-gate #include "msg.h" 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate #define FLG_VER_AVAIL 0x10 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate typedef struct cache { 73*0Sstevel@tonic-gate Elf_Scn *c_scn; 74*0Sstevel@tonic-gate Elf_Data *c_data; 75*0Sstevel@tonic-gate char *c_name; 76*0Sstevel@tonic-gate } Cache; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate typedef struct gver_desc { 79*0Sstevel@tonic-gate const char *vd_name; 80*0Sstevel@tonic-gate unsigned long vd_hash; 81*0Sstevel@tonic-gate GElf_Half vd_ndx; 82*0Sstevel@tonic-gate GElf_Half vd_flags; 83*0Sstevel@tonic-gate List vd_deps; 84*0Sstevel@tonic-gate } GVer_desc; 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate static const char *cname; 87*0Sstevel@tonic-gate static int Cflag, dflag, lflag, nflag, oflag, rflag, sflag, vflag; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate static const char 90*0Sstevel@tonic-gate * Format_ofil = "%s -", 91*0Sstevel@tonic-gate * Format_tnco = "\t%s:\n", 92*0Sstevel@tonic-gate * Format_tnse = "\t%s;\n", 93*0Sstevel@tonic-gate * Format_bgnl = "\t%s (%s", 94*0Sstevel@tonic-gate * Format_next = ", %s", 95*0Sstevel@tonic-gate * Format_weak = " [WEAK]", 96*0Sstevel@tonic-gate * Format_endl = ");\n"; 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate #define DEF_DEFINED 1 99*0Sstevel@tonic-gate #define USR_DEFINED 2 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate /* 102*0Sstevel@tonic-gate * Determine whether a symbol name should be demangled. 103*0Sstevel@tonic-gate */ 104*0Sstevel@tonic-gate static const char * 105*0Sstevel@tonic-gate demangle(const char *name) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate if (Cflag) 108*0Sstevel@tonic-gate return (Gelf_sym_dem(name)); 109*0Sstevel@tonic-gate else 110*0Sstevel@tonic-gate return (name); 111*0Sstevel@tonic-gate } 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * Define our own printing routine. We don't actually use this, but because 116*0Sstevel@tonic-gate * we use liblddbg to demangle symbols we need to provide this to satisfy 117*0Sstevel@tonic-gate * liblddbg's binding requirements. 118*0Sstevel@tonic-gate */ 119*0Sstevel@tonic-gate /*PRINTFLIKE1*/ 120*0Sstevel@tonic-gate void 121*0Sstevel@tonic-gate dbg_print(const char *format, ...) 122*0Sstevel@tonic-gate { 123*0Sstevel@tonic-gate va_list ap; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate va_start(ap, format); 126*0Sstevel@tonic-gate (void) vprintf(format, ap); 127*0Sstevel@tonic-gate (void) printf(MSG_ORIG(MSG_STR_NL)); 128*0Sstevel@tonic-gate } 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate /* 132*0Sstevel@tonic-gate * Print any reduced symbols. The convention is that reduced symbols exist as 133*0Sstevel@tonic-gate * LOCL entries in the .symtab, between the FILE symbol for the output file and 134*0Sstevel@tonic-gate * the first FILE symbol for any input file used to build the output file. 135*0Sstevel@tonic-gate */ 136*0Sstevel@tonic-gate static void 137*0Sstevel@tonic-gate sym_local(Cache *cache, Cache *csym, const char *file) 138*0Sstevel@tonic-gate { 139*0Sstevel@tonic-gate int symn, _symn, found = 0; 140*0Sstevel@tonic-gate GElf_Shdr shdr; 141*0Sstevel@tonic-gate GElf_Sym sym; 142*0Sstevel@tonic-gate char *strs, *local = "_LOCAL_"; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate (void) gelf_getshdr(csym->c_scn, &shdr); 145*0Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 146*0Sstevel@tonic-gate /* LINTED */ 147*0Sstevel@tonic-gate symn = shdr.sh_info; 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate /* 150*0Sstevel@tonic-gate * Verify symtab[1] is the output file symbol. 151*0Sstevel@tonic-gate */ 152*0Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, 1, &sym); 153*0Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) != STT_FILE) { 154*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), cname, 155*0Sstevel@tonic-gate file); 156*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOTSTTFILE), 157*0Sstevel@tonic-gate csym->c_name); 158*0Sstevel@tonic-gate return; 159*0Sstevel@tonic-gate } 160*0Sstevel@tonic-gate 161*0Sstevel@tonic-gate /* 162*0Sstevel@tonic-gate * Scan the remaining symbols until the next file symbol is found. 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate for (_symn = 2; _symn < symn; _symn++) { 165*0Sstevel@tonic-gate const char *name; 166*0Sstevel@tonic-gate 167*0Sstevel@tonic-gate (void) gelf_getsym(csym->c_data, _symn, &sym); 168*0Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) 169*0Sstevel@tonic-gate continue; 170*0Sstevel@tonic-gate if (GELF_ST_TYPE(sym.st_info) == STT_FILE) 171*0Sstevel@tonic-gate break; 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * Its possible that section symbols are followed immediately 175*0Sstevel@tonic-gate * by globals. This is the case if an object (filter) is 176*0Sstevel@tonic-gate * generated exclusively from mapfile symbol definitions. 177*0Sstevel@tonic-gate */ 178*0Sstevel@tonic-gate if (GELF_ST_BIND(sym.st_info) != STB_LOCAL) 179*0Sstevel@tonic-gate break; 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate name = demangle(strs + sym.st_name); 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate if (oflag) { 184*0Sstevel@tonic-gate (void) printf(Format_ofil, file); 185*0Sstevel@tonic-gate (void) printf("\t%s: %s\n", local, name); 186*0Sstevel@tonic-gate } else { 187*0Sstevel@tonic-gate if (found == 0) { 188*0Sstevel@tonic-gate found = 1; 189*0Sstevel@tonic-gate (void) printf(Format_tnco, local); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate (void) printf("\t\t%s;\n", name); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate } 195*0Sstevel@tonic-gate 196*0Sstevel@tonic-gate /* 197*0Sstevel@tonic-gate * Print the files version needed sections. 198*0Sstevel@tonic-gate */ 199*0Sstevel@tonic-gate static int 200*0Sstevel@tonic-gate gvers_need(Cache *cache, Cache *need, const char *file, const char *name) 201*0Sstevel@tonic-gate { 202*0Sstevel@tonic-gate unsigned int num, _num; 203*0Sstevel@tonic-gate char *strs; 204*0Sstevel@tonic-gate GElf_Verneed *vnd = need->c_data->d_buf; 205*0Sstevel@tonic-gate GElf_Shdr shdr; 206*0Sstevel@tonic-gate int error = 0; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate (void) gelf_getshdr(need->c_scn, &shdr); 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate /* 211*0Sstevel@tonic-gate * Verify the version revision. We only check the first version 212*0Sstevel@tonic-gate * structure as it is assumed all other version structures in this 213*0Sstevel@tonic-gate * data section will be of the same revision. 214*0Sstevel@tonic-gate */ 215*0Sstevel@tonic-gate if (vnd->vn_version > VER_DEF_CURRENT) 216*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 217*0Sstevel@tonic-gate vnd->vn_version, VER_DEF_CURRENT); 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate /* 220*0Sstevel@tonic-gate * Get the data buffer for the associated string table. 221*0Sstevel@tonic-gate */ 222*0Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 223*0Sstevel@tonic-gate num = shdr.sh_info; 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 226*0Sstevel@tonic-gate vnd = (GElf_Verneed *)((uintptr_t)vnd + vnd->vn_next)) { 227*0Sstevel@tonic-gate GElf_Vernaux *vnap = (GElf_Vernaux *) 228*0Sstevel@tonic-gate ((uintptr_t)vnd + vnd->vn_aux); 229*0Sstevel@tonic-gate GElf_Half cnt = vnd->vn_cnt; 230*0Sstevel@tonic-gate const char *_name, * dep; 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate /* 233*0Sstevel@tonic-gate * Obtain the version name and determine if we need to process 234*0Sstevel@tonic-gate * it further. 235*0Sstevel@tonic-gate */ 236*0Sstevel@tonic-gate _name = (char *)(strs + vnd->vn_file); 237*0Sstevel@tonic-gate if (name && (strcmp(name, _name) == 0)) 238*0Sstevel@tonic-gate continue; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate error = 1; 241*0Sstevel@tonic-gate 242*0Sstevel@tonic-gate /* 243*0Sstevel@tonic-gate * If one-line ouput is called for display the filename being 244*0Sstevel@tonic-gate * processed. 245*0Sstevel@tonic-gate */ 246*0Sstevel@tonic-gate if (oflag) 247*0Sstevel@tonic-gate (void) printf(Format_ofil, file); 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate /* 250*0Sstevel@tonic-gate * Determine the version name required from this file. 251*0Sstevel@tonic-gate */ 252*0Sstevel@tonic-gate if (cnt--) 253*0Sstevel@tonic-gate dep = (char *)(strs + vnap->vna_name); 254*0Sstevel@tonic-gate else 255*0Sstevel@tonic-gate dep = MSG_ORIG(MSG_STR_EMPTY); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate (void) printf(Format_bgnl, _name, dep); 258*0Sstevel@tonic-gate if (vflag && (vnap->vna_flags == VER_FLG_WEAK)) 259*0Sstevel@tonic-gate (void) printf(Format_weak); 260*0Sstevel@tonic-gate 261*0Sstevel@tonic-gate /* 262*0Sstevel@tonic-gate * Extract any other version dependencies for this file 263*0Sstevel@tonic-gate */ 264*0Sstevel@tonic-gate /* CSTYLED */ 265*0Sstevel@tonic-gate for (vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next); 266*0Sstevel@tonic-gate cnt; cnt--, 267*0Sstevel@tonic-gate vnap = (GElf_Vernaux *)((uintptr_t)vnap + vnap->vna_next)) { 268*0Sstevel@tonic-gate dep = (char *)(strs + vnap->vna_name); 269*0Sstevel@tonic-gate (void) printf(Format_next, dep); 270*0Sstevel@tonic-gate if (vflag && (vnap->vna_flags == VER_FLG_WEAK)) 271*0Sstevel@tonic-gate (void) printf(Format_weak); 272*0Sstevel@tonic-gate } 273*0Sstevel@tonic-gate (void) printf(Format_endl); 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate return (error); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate /* 279*0Sstevel@tonic-gate * Append an item to the specified list, and return a pointer to the list 280*0Sstevel@tonic-gate * node created. 281*0Sstevel@tonic-gate */ 282*0Sstevel@tonic-gate static Listnode * 283*0Sstevel@tonic-gate list_append(List *lst, const void *item, const char *file) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate Listnode *_lnp; 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate if ((_lnp = malloc(sizeof (Listnode))) == 0) { 288*0Sstevel@tonic-gate int err = errno; 289*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, file, 290*0Sstevel@tonic-gate strerror(err)); 291*0Sstevel@tonic-gate exit(1); 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate _lnp->data = (void *)item; 295*0Sstevel@tonic-gate _lnp->next = NULL; 296*0Sstevel@tonic-gate 297*0Sstevel@tonic-gate if (lst->head == NULL) 298*0Sstevel@tonic-gate lst->tail = lst->head = _lnp; 299*0Sstevel@tonic-gate else { 300*0Sstevel@tonic-gate lst->tail->next = _lnp; 301*0Sstevel@tonic-gate lst->tail = lst->tail->next; 302*0Sstevel@tonic-gate } 303*0Sstevel@tonic-gate return (_lnp); 304*0Sstevel@tonic-gate } 305*0Sstevel@tonic-gate 306*0Sstevel@tonic-gate static GVer_desc * 307*0Sstevel@tonic-gate gvers_find(const char *name, unsigned long hash, List *lst) 308*0Sstevel@tonic-gate { 309*0Sstevel@tonic-gate Listnode *lnp; 310*0Sstevel@tonic-gate GVer_desc *vdp; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate for (LIST_TRAVERSE(lst, lnp, vdp)) { 313*0Sstevel@tonic-gate if (vdp->vd_hash != hash) 314*0Sstevel@tonic-gate continue; 315*0Sstevel@tonic-gate if (strcmp(vdp->vd_name, name) == 0) 316*0Sstevel@tonic-gate return (vdp); 317*0Sstevel@tonic-gate } 318*0Sstevel@tonic-gate return (0); 319*0Sstevel@tonic-gate } 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate static GVer_desc * 322*0Sstevel@tonic-gate gvers_desc(const char *name, unsigned long hash, List *lst, const char *file) 323*0Sstevel@tonic-gate { 324*0Sstevel@tonic-gate GVer_desc *vdp; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if ((vdp = gvers_find(name, hash, lst)) == 0) { 327*0Sstevel@tonic-gate if ((vdp = calloc(sizeof (GVer_desc), 1)) == 0) { 328*0Sstevel@tonic-gate int err = errno; 329*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 330*0Sstevel@tonic-gate file, strerror(err)); 331*0Sstevel@tonic-gate exit(1); 332*0Sstevel@tonic-gate } 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate vdp->vd_name = name; 335*0Sstevel@tonic-gate vdp->vd_hash = hash; 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate if (list_append(lst, vdp, file) == 0) 338*0Sstevel@tonic-gate return (0); 339*0Sstevel@tonic-gate } 340*0Sstevel@tonic-gate return (vdp); 341*0Sstevel@tonic-gate } 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate static GVer_desc * 344*0Sstevel@tonic-gate gvers_depend(const char *name, unsigned long hash, GVer_desc *vdp, List *lst, 345*0Sstevel@tonic-gate const char *file) 346*0Sstevel@tonic-gate { 347*0Sstevel@tonic-gate GVer_desc *_vdp; 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate if ((_vdp = gvers_desc(name, hash, lst, file)) == 0) 350*0Sstevel@tonic-gate return (0); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate if (list_append(&vdp->vd_deps, _vdp, file) == 0) 353*0Sstevel@tonic-gate return (0); 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate return (vdp); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate static void 359*0Sstevel@tonic-gate gvers_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs, 360*0Sstevel@tonic-gate GVer_desc *vdp, const char *file) 361*0Sstevel@tonic-gate { 362*0Sstevel@tonic-gate GElf_Sym sym; 363*0Sstevel@tonic-gate int _symn; 364*0Sstevel@tonic-gate 365*0Sstevel@tonic-gate for (_symn = 0; _symn < symn; _symn++) { 366*0Sstevel@tonic-gate size_t size = 0; 367*0Sstevel@tonic-gate const char *name; 368*0Sstevel@tonic-gate 369*0Sstevel@tonic-gate if (vsp[_symn] != vdp->vd_ndx) 370*0Sstevel@tonic-gate continue; 371*0Sstevel@tonic-gate 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * For data symbols determine the size. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate (void) gelf_getsym(sym_data, _symn, &sym); 376*0Sstevel@tonic-gate if ((GELF_ST_TYPE(sym.st_info) == STT_OBJECT) || 377*0Sstevel@tonic-gate (GELF_ST_TYPE(sym.st_info) == STT_COMMON) || 378*0Sstevel@tonic-gate (GELF_ST_TYPE(sym.st_info) == STT_TLS)) 379*0Sstevel@tonic-gate size = (size_t)sym.st_size; 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate name = demangle(strs + sym.st_name); 382*0Sstevel@tonic-gate 383*0Sstevel@tonic-gate /* 384*0Sstevel@tonic-gate * Only output the version symbol when the verbose flag is used. 385*0Sstevel@tonic-gate */ 386*0Sstevel@tonic-gate if (!vflag && (sym.st_shndx == SHN_ABS)) { 387*0Sstevel@tonic-gate if (strcmp(name, vdp->vd_name) == 0) 388*0Sstevel@tonic-gate continue; 389*0Sstevel@tonic-gate } 390*0Sstevel@tonic-gate 391*0Sstevel@tonic-gate if (oflag) { 392*0Sstevel@tonic-gate (void) printf(Format_ofil, file); 393*0Sstevel@tonic-gate (void) printf("\t%s: ", vdp->vd_name); 394*0Sstevel@tonic-gate if (size) 395*0Sstevel@tonic-gate (void) printf("%s (%ld);\n", name, 396*0Sstevel@tonic-gate (ulong_t)size); 397*0Sstevel@tonic-gate else 398*0Sstevel@tonic-gate (void) printf("%s;\n", name); 399*0Sstevel@tonic-gate } else { 400*0Sstevel@tonic-gate if (size) 401*0Sstevel@tonic-gate (void) printf("\t\t%s (%ld);\n", name, 402*0Sstevel@tonic-gate (ulong_t)size); 403*0Sstevel@tonic-gate else 404*0Sstevel@tonic-gate (void) printf("\t\t%s;\n", name); 405*0Sstevel@tonic-gate } 406*0Sstevel@tonic-gate } 407*0Sstevel@tonic-gate } 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate static void 410*0Sstevel@tonic-gate gvers_derefer(GVer_desc * vdp, int weak) 411*0Sstevel@tonic-gate { 412*0Sstevel@tonic-gate Listnode * _lnp; 413*0Sstevel@tonic-gate GVer_desc * _vdp; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * If the head of the list was a weak then we only clear out 417*0Sstevel@tonic-gate * weak dependencies, but if the head of the list was 'strong' 418*0Sstevel@tonic-gate * we clear the REFER bit on all dependencies. 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate if ((weak && (vdp->vd_flags & VER_FLG_WEAK)) || (!weak)) 421*0Sstevel@tonic-gate vdp->vd_flags &= ~FLG_VER_AVAIL; 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) 424*0Sstevel@tonic-gate gvers_derefer(_vdp, weak); 425*0Sstevel@tonic-gate } 426*0Sstevel@tonic-gate 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate static void 429*0Sstevel@tonic-gate recurse_syms(GElf_Versym *vsp, Elf_Data *sym_data, int symn, char *strs, 430*0Sstevel@tonic-gate GVer_desc *vdp, const char *file) 431*0Sstevel@tonic-gate { 432*0Sstevel@tonic-gate Listnode *_lnp; 433*0Sstevel@tonic-gate GVer_desc *_vdp; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) { 436*0Sstevel@tonic-gate if (!oflag) 437*0Sstevel@tonic-gate (void) printf(Format_tnco, _vdp->vd_name); 438*0Sstevel@tonic-gate gvers_syms(vsp, sym_data, symn, strs, _vdp, file); 439*0Sstevel@tonic-gate if (_vdp->vd_deps.head) 440*0Sstevel@tonic-gate recurse_syms(vsp, sym_data, symn, strs, _vdp, file); 441*0Sstevel@tonic-gate } 442*0Sstevel@tonic-gate } 443*0Sstevel@tonic-gate 444*0Sstevel@tonic-gate 445*0Sstevel@tonic-gate /* 446*0Sstevel@tonic-gate * Print the files version definition sections. 447*0Sstevel@tonic-gate */ 448*0Sstevel@tonic-gate static int 449*0Sstevel@tonic-gate gvers_def(Cache *cache, Cache *def, Cache *csym, const char *file, 450*0Sstevel@tonic-gate const char *name) 451*0Sstevel@tonic-gate { 452*0Sstevel@tonic-gate unsigned int num, _num; 453*0Sstevel@tonic-gate char *strs; 454*0Sstevel@tonic-gate GElf_Versym *vsp; 455*0Sstevel@tonic-gate GElf_Verdef *vdf = def->c_data->d_buf; 456*0Sstevel@tonic-gate GElf_Shdr shdr; 457*0Sstevel@tonic-gate Elf_Data *sym_data; 458*0Sstevel@tonic-gate int symn; 459*0Sstevel@tonic-gate GVer_desc *vdp, *bvdp = 0; 460*0Sstevel@tonic-gate Listnode *lnp; 461*0Sstevel@tonic-gate List verdefs = {0, 0}; 462*0Sstevel@tonic-gate int error = 0; 463*0Sstevel@tonic-gate 464*0Sstevel@tonic-gate /* 465*0Sstevel@tonic-gate * Verify the version revision. We only check the first version 466*0Sstevel@tonic-gate * structure as it is assumed all other version structures in this 467*0Sstevel@tonic-gate * data section will be of the same revision. 468*0Sstevel@tonic-gate */ 469*0Sstevel@tonic-gate if (vdf->vd_version > VER_DEF_CURRENT) { 470*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_HIGHREV), cname, file, 471*0Sstevel@tonic-gate vdf->vd_version, VER_DEF_CURRENT); 472*0Sstevel@tonic-gate } 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate /* 475*0Sstevel@tonic-gate * Get the data buffer for the associated string table. 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate (void) gelf_getshdr(def->c_scn, &shdr); 478*0Sstevel@tonic-gate strs = (char *)cache[shdr.sh_link].c_data->d_buf; 479*0Sstevel@tonic-gate num = shdr.sh_info; 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate /* 482*0Sstevel@tonic-gate * Process the version definitions placing each on a version dependency 483*0Sstevel@tonic-gate * list. 484*0Sstevel@tonic-gate */ 485*0Sstevel@tonic-gate for (_num = 1; _num <= num; _num++, 486*0Sstevel@tonic-gate vdf = (GElf_Verdef *)((uintptr_t)vdf + vdf->vd_next)) { 487*0Sstevel@tonic-gate GElf_Half cnt = vdf->vd_cnt; 488*0Sstevel@tonic-gate GElf_Half ndx = vdf->vd_ndx; 489*0Sstevel@tonic-gate GElf_Verdaux *vdap = (GElf_Verdaux *)((uintptr_t)vdf + 490*0Sstevel@tonic-gate vdf->vd_aux); 491*0Sstevel@tonic-gate const char *_name; 492*0Sstevel@tonic-gate 493*0Sstevel@tonic-gate /* 494*0Sstevel@tonic-gate * Determine the version name and any dependencies. 495*0Sstevel@tonic-gate */ 496*0Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate if ((vdp = gvers_desc(_name, elf_hash(_name), &verdefs, 499*0Sstevel@tonic-gate file)) == 0) 500*0Sstevel@tonic-gate return (0); 501*0Sstevel@tonic-gate vdp->vd_ndx = ndx; 502*0Sstevel@tonic-gate vdp->vd_flags = vdf->vd_flags | FLG_VER_AVAIL; 503*0Sstevel@tonic-gate 504*0Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next); 505*0Sstevel@tonic-gate for (cnt--; cnt; cnt--, 506*0Sstevel@tonic-gate vdap = (GElf_Verdaux *)((uintptr_t)vdap + vdap->vda_next)) { 507*0Sstevel@tonic-gate _name = (char *)(strs + vdap->vda_name); 508*0Sstevel@tonic-gate if (gvers_depend(_name, elf_hash(_name), vdp, 509*0Sstevel@tonic-gate &verdefs, file) == 0) 510*0Sstevel@tonic-gate return (0); 511*0Sstevel@tonic-gate } 512*0Sstevel@tonic-gate 513*0Sstevel@tonic-gate /* 514*0Sstevel@tonic-gate * Remember the base version for possible later use. 515*0Sstevel@tonic-gate */ 516*0Sstevel@tonic-gate if (ndx == VER_NDX_GLOBAL) 517*0Sstevel@tonic-gate bvdp = vdp; 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate /* 521*0Sstevel@tonic-gate * Normalize the dependency list if required. 522*0Sstevel@tonic-gate */ 523*0Sstevel@tonic-gate if (nflag) { 524*0Sstevel@tonic-gate for (LIST_TRAVERSE(&verdefs, lnp, vdp)) { 525*0Sstevel@tonic-gate Listnode * _lnp; 526*0Sstevel@tonic-gate GVer_desc * _vdp; 527*0Sstevel@tonic-gate int type = vdp->vd_flags & VER_FLG_WEAK; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) 530*0Sstevel@tonic-gate gvers_derefer(_vdp, type); 531*0Sstevel@tonic-gate } 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate /* 534*0Sstevel@tonic-gate * Always dereference the base version. 535*0Sstevel@tonic-gate */ 536*0Sstevel@tonic-gate if (bvdp) 537*0Sstevel@tonic-gate bvdp->vd_flags &= ~FLG_VER_AVAIL; 538*0Sstevel@tonic-gate } 539*0Sstevel@tonic-gate 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /* 542*0Sstevel@tonic-gate * Traverse the dependency list and print out the appropriate 543*0Sstevel@tonic-gate * information. 544*0Sstevel@tonic-gate */ 545*0Sstevel@tonic-gate for (LIST_TRAVERSE(&verdefs, lnp, vdp)) { 546*0Sstevel@tonic-gate Listnode * _lnp; 547*0Sstevel@tonic-gate GVer_desc * _vdp; 548*0Sstevel@tonic-gate int count; 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate if (name && (strcmp(name, vdp->vd_name) != 0)) 551*0Sstevel@tonic-gate continue; 552*0Sstevel@tonic-gate 553*0Sstevel@tonic-gate if (!name && !(vdp->vd_flags & FLG_VER_AVAIL)) 554*0Sstevel@tonic-gate continue; 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate error = 1; 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate if (vflag) { 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * If the verbose flag is set determine if this version 561*0Sstevel@tonic-gate * has a `weak' attribute, and print any version 562*0Sstevel@tonic-gate * dependencies this version inherits. 563*0Sstevel@tonic-gate */ 564*0Sstevel@tonic-gate if (oflag) 565*0Sstevel@tonic-gate (void) printf(Format_ofil, file); 566*0Sstevel@tonic-gate (void) printf("\t%s", vdp->vd_name); 567*0Sstevel@tonic-gate if (vdp->vd_flags & VER_FLG_WEAK) 568*0Sstevel@tonic-gate (void) printf(Format_weak); 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate count = 1; 571*0Sstevel@tonic-gate for (LIST_TRAVERSE(&vdp->vd_deps, _lnp, _vdp)) { 572*0Sstevel@tonic-gate const char *_name = _vdp->vd_name; 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if (count++ == 1) { 575*0Sstevel@tonic-gate if (oflag) 576*0Sstevel@tonic-gate (void) printf(": {%s", _name); 577*0Sstevel@tonic-gate else if (vdp->vd_flags & VER_FLG_WEAK) 578*0Sstevel@tonic-gate (void) printf(":\t{%s", _name); 579*0Sstevel@tonic-gate else 580*0Sstevel@tonic-gate (void) printf(": \t{%s", 581*0Sstevel@tonic-gate _name); 582*0Sstevel@tonic-gate } else 583*0Sstevel@tonic-gate (void) printf(Format_next, _name); 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate 586*0Sstevel@tonic-gate if (count != 1) 587*0Sstevel@tonic-gate (void) printf("}"); 588*0Sstevel@tonic-gate 589*0Sstevel@tonic-gate if (csym && !oflag) 590*0Sstevel@tonic-gate (void) printf(":\n"); 591*0Sstevel@tonic-gate else 592*0Sstevel@tonic-gate (void) printf(";\n"); 593*0Sstevel@tonic-gate } else { 594*0Sstevel@tonic-gate if (csym && !oflag) 595*0Sstevel@tonic-gate (void) printf(Format_tnco, vdp->vd_name); 596*0Sstevel@tonic-gate else if (!csym) { 597*0Sstevel@tonic-gate if (oflag) 598*0Sstevel@tonic-gate (void) printf(Format_ofil, file); 599*0Sstevel@tonic-gate (void) printf(Format_tnse, vdp->vd_name); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate } 602*0Sstevel@tonic-gate 603*0Sstevel@tonic-gate /* 604*0Sstevel@tonic-gate * If we need to print symbols get the associated symbol table. 605*0Sstevel@tonic-gate */ 606*0Sstevel@tonic-gate if (csym) { 607*0Sstevel@tonic-gate (void) gelf_getshdr(csym->c_scn, &shdr); 608*0Sstevel@tonic-gate vsp = (GElf_Versym *)csym->c_data->d_buf; 609*0Sstevel@tonic-gate sym_data = cache[shdr.sh_link].c_data; 610*0Sstevel@tonic-gate (void) gelf_getshdr(cache[shdr.sh_link].c_scn, &shdr); 611*0Sstevel@tonic-gate /* LINTED */ 612*0Sstevel@tonic-gate symn = (int)(shdr.sh_size / shdr.sh_entsize); 613*0Sstevel@tonic-gate } else 614*0Sstevel@tonic-gate continue; 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate /* 617*0Sstevel@tonic-gate * If a specific version name has been specified then display 618*0Sstevel@tonic-gate * any of its own symbols plus any inherited from other 619*0Sstevel@tonic-gate * versions. Otherwise simply print out the symbols for this 620*0Sstevel@tonic-gate * version. 621*0Sstevel@tonic-gate */ 622*0Sstevel@tonic-gate gvers_syms(vsp, sym_data, symn, strs, vdp, file); 623*0Sstevel@tonic-gate if (name) { 624*0Sstevel@tonic-gate recurse_syms(vsp, sym_data, symn, strs, vdp, file); 625*0Sstevel@tonic-gate 626*0Sstevel@tonic-gate /* 627*0Sstevel@tonic-gate * If the verbose flag is set add the base version as a 628*0Sstevel@tonic-gate * dependency (unless it's the list we were asked to 629*0Sstevel@tonic-gate * print in the first place). 630*0Sstevel@tonic-gate */ 631*0Sstevel@tonic-gate if (vflag && bvdp && strcmp(name, bvdp->vd_name)) { 632*0Sstevel@tonic-gate if (!oflag) 633*0Sstevel@tonic-gate (void) printf(Format_tnco, bvdp->vd_name); 634*0Sstevel@tonic-gate gvers_syms(vsp, sym_data, symn, strs, bvdp, 635*0Sstevel@tonic-gate file); 636*0Sstevel@tonic-gate } 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate return (error); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate int 643*0Sstevel@tonic-gate main(int argc, char **argv, char **envp) 644*0Sstevel@tonic-gate { 645*0Sstevel@tonic-gate GElf_Shdr shdr; 646*0Sstevel@tonic-gate Elf *elf; 647*0Sstevel@tonic-gate Elf_Scn *scn; 648*0Sstevel@tonic-gate Elf_Data *data; 649*0Sstevel@tonic-gate GElf_Ehdr ehdr; 650*0Sstevel@tonic-gate int nfile, var; 651*0Sstevel@tonic-gate const char *name; 652*0Sstevel@tonic-gate char *names; 653*0Sstevel@tonic-gate Cache *cache, *_cache; 654*0Sstevel@tonic-gate Cache *_cache_def, *_cache_need, *_cache_sym, *_cache_loc; 655*0Sstevel@tonic-gate int error = 0; 656*0Sstevel@tonic-gate 657*0Sstevel@tonic-gate /* 658*0Sstevel@tonic-gate * Check for a binary that better fits this architecture. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate conv_check_native(argv, envp); 661*0Sstevel@tonic-gate 662*0Sstevel@tonic-gate /* 663*0Sstevel@tonic-gate * Establish locale. 664*0Sstevel@tonic-gate */ 665*0Sstevel@tonic-gate (void) setlocale(LC_MESSAGES, MSG_ORIG(MSG_STR_EMPTY)); 666*0Sstevel@tonic-gate (void) textdomain(MSG_ORIG(MSG_SUNW_OST_SGS)); 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate cname = argv[0]; 669*0Sstevel@tonic-gate name = NULL; 670*0Sstevel@tonic-gate Cflag = dflag = lflag = nflag = oflag = rflag = sflag = vflag = 0; 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate opterr = 0; 673*0Sstevel@tonic-gate while ((var = getopt(argc, argv, "CdlnorsvN:")) != EOF) { 674*0Sstevel@tonic-gate switch (var) { 675*0Sstevel@tonic-gate case 'C': 676*0Sstevel@tonic-gate Cflag = USR_DEFINED; 677*0Sstevel@tonic-gate break; 678*0Sstevel@tonic-gate case 'd': 679*0Sstevel@tonic-gate dflag = USR_DEFINED; 680*0Sstevel@tonic-gate break; 681*0Sstevel@tonic-gate case 'l': 682*0Sstevel@tonic-gate lflag = USR_DEFINED; 683*0Sstevel@tonic-gate break; 684*0Sstevel@tonic-gate case 'n': 685*0Sstevel@tonic-gate nflag = USR_DEFINED; 686*0Sstevel@tonic-gate break; 687*0Sstevel@tonic-gate case 'o': 688*0Sstevel@tonic-gate oflag = USR_DEFINED; 689*0Sstevel@tonic-gate break; 690*0Sstevel@tonic-gate case 'r': 691*0Sstevel@tonic-gate rflag = USR_DEFINED; 692*0Sstevel@tonic-gate break; 693*0Sstevel@tonic-gate case 's': 694*0Sstevel@tonic-gate sflag = USR_DEFINED; 695*0Sstevel@tonic-gate break; 696*0Sstevel@tonic-gate case 'v': 697*0Sstevel@tonic-gate vflag = USR_DEFINED; 698*0Sstevel@tonic-gate break; 699*0Sstevel@tonic-gate case 'N': 700*0Sstevel@tonic-gate name = optarg; 701*0Sstevel@tonic-gate break; 702*0Sstevel@tonic-gate case '?': 703*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), 704*0Sstevel@tonic-gate cname); 705*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_DETAIL)); 706*0Sstevel@tonic-gate exit(1); 707*0Sstevel@tonic-gate default: 708*0Sstevel@tonic-gate break; 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate } 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate /* 713*0Sstevel@tonic-gate * No files specified on the command line? 714*0Sstevel@tonic-gate */ 715*0Sstevel@tonic-gate if ((nfile = argc - optind) == 0) { 716*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_USAGE_BRIEF), cname); 717*0Sstevel@tonic-gate exit(1); 718*0Sstevel@tonic-gate } 719*0Sstevel@tonic-gate 720*0Sstevel@tonic-gate /* 721*0Sstevel@tonic-gate * By default print both version definitions and needed dependencies. 722*0Sstevel@tonic-gate */ 723*0Sstevel@tonic-gate if ((dflag == 0) && (rflag == 0)) 724*0Sstevel@tonic-gate dflag = rflag = DEF_DEFINED; 725*0Sstevel@tonic-gate 726*0Sstevel@tonic-gate /* 727*0Sstevel@tonic-gate * Open the input file and initialize the elf interface. 728*0Sstevel@tonic-gate */ 729*0Sstevel@tonic-gate for (; optind < argc; optind++) { 730*0Sstevel@tonic-gate int derror = 0, nerror = 0, err; 731*0Sstevel@tonic-gate const char *file = argv[optind]; 732*0Sstevel@tonic-gate 733*0Sstevel@tonic-gate if ((var = open(file, O_RDONLY)) == -1) { 734*0Sstevel@tonic-gate err = errno; 735*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_OPEN), 736*0Sstevel@tonic-gate cname, file, strerror(err)); 737*0Sstevel@tonic-gate error = 1; 738*0Sstevel@tonic-gate continue; 739*0Sstevel@tonic-gate } 740*0Sstevel@tonic-gate (void) elf_version(EV_CURRENT); 741*0Sstevel@tonic-gate if ((elf = elf_begin(var, ELF_C_READ, NULL)) == NULL) { 742*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_BEGIN), cname, 743*0Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 744*0Sstevel@tonic-gate error = 1; 745*0Sstevel@tonic-gate (void) close(var); 746*0Sstevel@tonic-gate continue; 747*0Sstevel@tonic-gate } 748*0Sstevel@tonic-gate if (elf_kind(elf) != ELF_K_ELF) { 749*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_ELF_NOTELF), cname, 750*0Sstevel@tonic-gate file); 751*0Sstevel@tonic-gate error = 1; 752*0Sstevel@tonic-gate (void) close(var); 753*0Sstevel@tonic-gate (void) elf_end(elf); 754*0Sstevel@tonic-gate continue; 755*0Sstevel@tonic-gate } 756*0Sstevel@tonic-gate if (gelf_getehdr(elf, &ehdr) == NULL) { 757*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETEHDR), cname, 758*0Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 759*0Sstevel@tonic-gate error = 1; 760*0Sstevel@tonic-gate (void) close(var); 761*0Sstevel@tonic-gate (void) elf_end(elf); 762*0Sstevel@tonic-gate continue; 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate /* 766*0Sstevel@tonic-gate * Obtain the .shstrtab data buffer to provide the required 767*0Sstevel@tonic-gate * section name strings. 768*0Sstevel@tonic-gate */ 769*0Sstevel@tonic-gate if ((scn = elf_getscn(elf, ehdr.e_shstrndx)) == NULL) { 770*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETSCN), cname, 771*0Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 772*0Sstevel@tonic-gate error = 1; 773*0Sstevel@tonic-gate (void) close(var); 774*0Sstevel@tonic-gate (void) elf_end(elf); 775*0Sstevel@tonic-gate continue; 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate if ((data = elf_getdata(scn, NULL)) == NULL) { 778*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_ORIG(MSG_ELF_GETDATA), cname, 779*0Sstevel@tonic-gate file, elf_errmsg(elf_errno())); 780*0Sstevel@tonic-gate error = 1; 781*0Sstevel@tonic-gate (void) close(var); 782*0Sstevel@tonic-gate (void) elf_end(elf); 783*0Sstevel@tonic-gate continue; 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate names = data->d_buf; 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate /* 788*0Sstevel@tonic-gate * Fill in the cache descriptor with information for each 789*0Sstevel@tonic-gate * section we might need. We probably only need to save 790*0Sstevel@tonic-gate * read-only allocable sections as this is where the version 791*0Sstevel@tonic-gate * structures and their associated symbols and strings live. 792*0Sstevel@tonic-gate * However, God knows what someone can do with a mapfile, and 793*0Sstevel@tonic-gate * as elf_begin has already gone through all the overhead we 794*0Sstevel@tonic-gate * might as well set up the cache for every section. 795*0Sstevel@tonic-gate */ 796*0Sstevel@tonic-gate if ((cache = calloc(ehdr.e_shnum, sizeof (Cache))) == 0) { 797*0Sstevel@tonic-gate int err = errno; 798*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_SYS_MALLOC), cname, 799*0Sstevel@tonic-gate file, strerror(err)); 800*0Sstevel@tonic-gate exit(1); 801*0Sstevel@tonic-gate } 802*0Sstevel@tonic-gate 803*0Sstevel@tonic-gate _cache_def = _cache_need = _cache_sym = _cache_loc = 0; 804*0Sstevel@tonic-gate _cache = cache; 805*0Sstevel@tonic-gate _cache++; 806*0Sstevel@tonic-gate for (scn = NULL; scn = elf_nextscn(elf, scn); _cache++) { 807*0Sstevel@tonic-gate if (gelf_getshdr(scn, &shdr) == NULL) { 808*0Sstevel@tonic-gate (void) fprintf(stderr, 809*0Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETSHDR), cname, file, 810*0Sstevel@tonic-gate elf_errmsg(elf_errno())); 811*0Sstevel@tonic-gate error = 1; 812*0Sstevel@tonic-gate continue; 813*0Sstevel@tonic-gate } 814*0Sstevel@tonic-gate if ((_cache->c_data = elf_getdata(scn, NULL)) == 815*0Sstevel@tonic-gate NULL) { 816*0Sstevel@tonic-gate (void) fprintf(stderr, 817*0Sstevel@tonic-gate MSG_ORIG(MSG_ELF_GETDATA), cname, file, 818*0Sstevel@tonic-gate elf_errmsg(elf_errno())); 819*0Sstevel@tonic-gate error = 1; 820*0Sstevel@tonic-gate continue; 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate _cache->c_scn = scn; 823*0Sstevel@tonic-gate _cache->c_name = names + shdr.sh_name; 824*0Sstevel@tonic-gate 825*0Sstevel@tonic-gate /* 826*0Sstevel@tonic-gate * Remember the version sections and symbol table. 827*0Sstevel@tonic-gate */ 828*0Sstevel@tonic-gate if ((shdr.sh_type == SHT_SUNW_verdef) && dflag) 829*0Sstevel@tonic-gate _cache_def = _cache; 830*0Sstevel@tonic-gate else if ((shdr.sh_type == SHT_SUNW_verneed) && rflag) 831*0Sstevel@tonic-gate _cache_need = _cache; 832*0Sstevel@tonic-gate else if ((shdr.sh_type == SHT_SUNW_versym) && sflag) 833*0Sstevel@tonic-gate _cache_sym = _cache; 834*0Sstevel@tonic-gate else if ((shdr.sh_type == SHT_SYMTAB) && lflag) 835*0Sstevel@tonic-gate _cache_loc = _cache; 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate /* 839*0Sstevel@tonic-gate * Before printing anything out determine if any warnings are 840*0Sstevel@tonic-gate * necessary. 841*0Sstevel@tonic-gate */ 842*0Sstevel@tonic-gate if (lflag && (_cache_loc == 0)) { 843*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_UNREDSYMS), 844*0Sstevel@tonic-gate cname, file); 845*0Sstevel@tonic-gate (void) fprintf(stderr, MSG_INTL(MSG_VER_NOSYMTAB)); 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate /* 849*0Sstevel@tonic-gate * If there is more than one input file, and we're not printing 850*0Sstevel@tonic-gate * one-line output, display the filename being processed. 851*0Sstevel@tonic-gate */ 852*0Sstevel@tonic-gate if ((nfile > 1) && !oflag) 853*0Sstevel@tonic-gate (void) printf("%s:\n", file); 854*0Sstevel@tonic-gate 855*0Sstevel@tonic-gate /* 856*0Sstevel@tonic-gate * Print the files version needed sections. 857*0Sstevel@tonic-gate */ 858*0Sstevel@tonic-gate if (_cache_need) 859*0Sstevel@tonic-gate nerror = gvers_need(cache, _cache_need, file, name); 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate /* 862*0Sstevel@tonic-gate * Print the files version definition sections. 863*0Sstevel@tonic-gate */ 864*0Sstevel@tonic-gate if (_cache_def) 865*0Sstevel@tonic-gate derror = gvers_def(cache, _cache_def, _cache_sym, 866*0Sstevel@tonic-gate file, name); 867*0Sstevel@tonic-gate 868*0Sstevel@tonic-gate /* 869*0Sstevel@tonic-gate * Print any local symbol reductions. 870*0Sstevel@tonic-gate */ 871*0Sstevel@tonic-gate if (_cache_loc) 872*0Sstevel@tonic-gate sym_local(cache, _cache_loc, file); 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate /* 875*0Sstevel@tonic-gate * Determine the error return. There are three conditions that 876*0Sstevel@tonic-gate * may produce an error (a non-zero return): 877*0Sstevel@tonic-gate * 878*0Sstevel@tonic-gate * o if the user specified -d and no version definitions 879*0Sstevel@tonic-gate * were found. 880*0Sstevel@tonic-gate * 881*0Sstevel@tonic-gate * o if the user specified -r and no version requirements 882*0Sstevel@tonic-gate * were found. 883*0Sstevel@tonic-gate * 884*0Sstevel@tonic-gate * o if the user specified neither -d or -r, (thus both are 885*0Sstevel@tonic-gate * enabled by default), and no version definitions or 886*0Sstevel@tonic-gate * version dependencies were found. 887*0Sstevel@tonic-gate */ 888*0Sstevel@tonic-gate if (((dflag == USR_DEFINED) && (derror == 0)) || 889*0Sstevel@tonic-gate ((rflag == USR_DEFINED) && (nerror == 0)) || 890*0Sstevel@tonic-gate (rflag && dflag && (derror == 0) && (nerror == 0))) 891*0Sstevel@tonic-gate error = 1; 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate (void) close(var); 894*0Sstevel@tonic-gate (void) elf_end(elf); 895*0Sstevel@tonic-gate free(cache); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate return (error); 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate 900*0Sstevel@tonic-gate const char * 901*0Sstevel@tonic-gate _pvs_msg(Msg mid) 902*0Sstevel@tonic-gate { 903*0Sstevel@tonic-gate return (gettext(MSG_ORIG(mid))); 904*0Sstevel@tonic-gate } 905