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